Pure maths, clock, text, and unit helpers that need no watch SDK. More...
Files | |
| file | src/c/core/clock/astro.c |
| Pure astronomy math, host-testable off-device. | |
| file | src/c/core/clock/astro.h |
| Pure astronomy math you can test off the watch. Right now just the Julian Date, worked out from a UTC timestamp with plain integer math, so it needs no Pebble services and no floats. | |
| file | src/c/core/clock/beats.c |
| Pure swatch .beats math, host-testable off-device. | |
| file | src/c/core/clock/beats.h |
| Pure swatch .beats math, operates on ms since Biel Mean Time (UTC+1) midnight. Also holds the token a date format uses to ask for a .beats reading. | |
| file | src/c/core/clock/date.c |
| Pure calendar math, host-testable off-device. | |
| file | src/c/core/clock/date.h |
| Pure calendar math you can test off the watch. Week numbers, day counts, and month shapes worked out from plain numbers, so it needs no Pebble services and no struct tm. | |
| file | src/c/core/clock/duration.c |
| A minute count turned into a short human duration. | |
| file | src/c/core/clock/duration.h |
| A minute count turned into a short human duration, no SDK. | |
| file | src/c/core/clock/hour_latch.c |
| The hourly buzz latch, host-testable off-device. | |
| file | src/c/core/clock/hour_latch.h |
| Decides when an hourly buzz fires, so it fires once for each real hour. | |
| file | src/c/core/clock/moon.c |
| Pure moon-phase math, host-testable off-device. | |
| file | src/c/core/clock/moon.h |
| Pure moon-phase math you can test off the watch. It counts from a known new moon using the average length of a moon cycle, so it needs nothing but a UTC timestamp. | |
| file | src/c/core/clock/nightsched.c |
| The night window, by containment rather than by edge. | |
| file | src/c/core/clock/nightsched.h |
| Whether a night-time window is open right now, from plain clock readings. | |
| file | src/c/core/clock/rotate.c |
| Working out which one is up from the clock. | |
| file | src/c/core/clock/rotate.h |
| Which one of a set to show right now, on a timed rotation. | |
| file | src/c/core/clock/solar.c |
| How the day's light is going, worked out from three plain clock readings. | |
| file | src/c/core/clock/solar.h |
| How the day's light is going, worked out from three plain clock readings. | |
| file | src/c/core/clock/tide.c |
| The rise and fall of a semidiurnal tide, from a plain running minute count. | |
| file | src/c/core/clock/tide.h |
| The rise and fall of a semidiurnal tide, from a plain running minute count. | |
| file | src/c/core/clock/timeband.c |
| The window sums: build one, place a moment on it, and clip a span to it. | |
| file | src/c/core/clock/timeband.h |
| A stretch of the day as an axis, and the sums that put a moment somewhere along it. | |
| file | src/c/core/clock/weekday.c |
| Weekday names, host-testable off-device. | |
| file | src/c/core/clock/weekday.h |
| Short weekday names shared by the panels that label a day. | |
| file | src/c/core/clock/zone_setting.c |
| Reads a time zone setting the way the phone sends it. | |
| file | src/c/core/clock/zone_setting.h |
| Reads a time zone setting the way the phone sends it, the minutes ahead of UTC then a comma and the place's name, as in "60,London". An empty setting means no zone is picked, which is what the phone sends once the wearer clears the picker. | |
| file | src/c/core/health/minute_window.c |
| Where a run of minute records lands in a window that ends at a given minute. | |
| file | src/c/core/health/minute_window.h |
| Where a run of minute records lands in a window that ends at a given minute. | |
| file | src/c/core/health/step_hours.c |
| The hour arithmetic behind the step chart's buckets. | |
| file | src/c/core/health/step_hours.h |
| The hour arithmetic behind the step chart's buckets. | |
| file | src/c/core/io/bytes_le.h |
| Little-endian byte readers shared by the wire-decoding stores. | |
| file | src/c/core/io/callback_list.c |
| Adding to and running a callback list. | |
| file | src/c/core/io/callback_list.h |
| A short fixed list of callbacks, run in the order they were added. | |
| file | src/c/core/layout/layout_role.c |
| The deprecated layout_role_pick, forwarding to role_pick. | |
| file | src/c/core/layout/layout_role.h |
| Deprecated names for the day/night/Quiet Time picker that role.h provides. | |
| file | src/c/core/layout/layout_string.c |
| Walking a layout wire string far enough to answer whether it holds anything. | |
| file | src/c/core/layout/layout_string.h |
| Reading a layout wire string without parsing the whole thing. | |
| file | src/c/core/math/pct.c |
| Progress towards a goal, as a percent. | |
| file | src/c/core/math/pct.h |
| Progress towards a goal, as a percent. | |
| file | src/c/core/math/scale.c |
| The clamp and segment maths a bar or gauge is built from. | |
| file | src/c/core/math/scale.h |
| The clamp and segment maths a bar or gauge is built from, no SDK. | |
| file | src/c/core/math/series.c |
| Reducing a run of samples to the few numbers a chart draws from. | |
| file | src/c/core/math/series.h |
| Reducing a run of samples to the few numbers a chart draws from, no SDK. | |
| file | src/c/core/role/role.c |
| The order the day, night, and Quiet Time triggers are asked in. | |
| file | src/c/core/role/role.h |
| Which of day, night, and Quiet Time should be on screen right now. | |
| file | src/c/core/text/cstring_fit.h |
| Comparing a string against a fixed buffer it is about to be copied into. | |
| file | src/c/core/text/number_format.c |
| Pure number and string formatting, no SDK behind it. | |
| file | src/c/core/text/number_format.h |
| Pure number and string formatting, no SDK behind it. | |
| file | src/c/core/text/text_case.c |
| Pure ascii case helpers, no SDK behind them. | |
| file | src/c/core/text/text_case.h |
| Pure ascii case helpers, no SDK behind them. | |
| file | src/c/core/units/distance.c |
| Pure distance conversions and formatting, no SDK behind them. | |
| file | src/c/core/units/distance.h |
| Pure distance conversions and formatting, no SDK behind them. | |
| file | src/c/core/units/wind.c |
| Pure wind-speed conversions and unit labels, no SDK behind them. | |
| file | src/c/core/units/wind.h |
| Pure wind-speed conversions and unit labels, no SDK behind them. | |
| file | src/c/core/weather/forecast_age.c |
| How much of a forecast strip has already gone by. | |
| file | src/c/core/weather/forecast_age.h |
| How much of a forecast strip has already gone by, so a strip that stays on the watch after a missed fetch shows what is still to come rather than hours and days already over. | |
| file | src/c/core/weather/weather_reading.c |
| Turns one weather message into the reading a store keeps. | |
| file | src/c/core/weather/weather_reading.h |
| One weather message off the phone, and the reading it leaves behind. | |
| file | src/c/core/weather/wind_dir.c |
| The compass direction a wind is blowing from, as a bearing and as a sideways component. | |
| file | src/c/core/weather/wind_dir.h |
| The compass direction a wind is blowing from, as a bearing and as a sideways component. | |
| file | src/c/core/weather/wx_label.c |
| The short word a small slot shows for the sky. | |
| file | src/c/core/weather/wx_label.h |
| The short word a small slot shows for the sky, from the condition token the phone sends. | |
| file | src/c/core/wire/calendar_wire.c |
| The agenda as the phone packs it, and the reader that unpacks it. | |
| file | src/c/core/wire/calendar_wire.h |
| The agenda as the phone packs it, and the reader that unpacks it. | |
| file | src/c/core/wire/coords.c |
| Telling a real fix from the phone's way of saying it has none. | |
| file | src/c/core/wire/coords.h |
| Telling a real fix from the phone's way of saying it has none. | |
| file | src/c/core/wire/stock_wire.c |
| The watchlist as the phone packs it, and the reader that unpacks it. | |
| file | src/c/core/wire/stock_wire.h |
| The watchlist as the phone packs it, and the reader that unpacks it. | |
| file | src/c/core/wire/weather_wire.c |
| The forecast strips as the phone packs them, and the readers that unpack them. | |
| file | src/c/core/wire/weather_wire.h |
| The forecast strips as the phone packs them, and the readers that unpack them. | |
| file | src/c/core/wire/wire_caps.g.h |
| Strip caps and marker values shared by the phone and the watch. | |
| file | src/c/core/wire/wire_read.h |
| Reads the values the phone packs into a message. | |
Data Structures | |
| struct | HourLatch |
| Remembers the hour that last buzzed. More... | |
| struct | TimeBand |
| The stretch of day a band shows: where it starts and how long it runs. More... | |
| struct | TimeBandSpan |
| A span clipped to the window, in minutes past the window's start. More... | |
| struct | CallbackList |
| A list over storage its owner provides. Start it as {entries, max, 0}. More... | |
| struct | WeatherMessage |
| One weather message as the transport read it, before anything is kept. More... | |
| struct | WeatherState |
| The weather a store keeps, laid out as the blob it saves to flash. More... | |
| struct | WeatherClock |
| The watch's clock at the moment a message lands, broken apart. More... | |
| struct | CalendarEvent |
| One event. start and end are absolute epochs so the readouts stay fresh against the watch's own clock. The phone fills end with a sensible default when the feed omits DTEND. More... | |
| struct | CalendarStrip |
| The agenda strip. count is 0 until a reading lands. More... | |
| struct | StockSlot |
| One quote slot. When ok is false the symbol field carries a short status word ("RATE LIMIT" and friends) instead of a ticker so the watch has something to show. More... | |
| struct | StockStrip |
| The watchlist strip. count is 0 until a reading lands. More... | |
| struct | WeatherHourCol |
| One hourly forecast column: a sky code plus a temperature (WEATHER_NO_TEMP for none). More... | |
| struct | WeatherDayCol |
| One daily forecast column: a sky code plus the day's high and low. More... | |
| struct | WeatherHourly |
| The hourly strip. count is 0 until a reading lands. More... | |
| struct | WeatherDaily |
| The 7-day strip. count is 0 until a reading lands. More... | |
Macros | |
| #define | HOUR_LATCH_EMPTY {.last_start = -1} |
| a latch that has not buzzed yet | |
| #define | MOON_SYNODIC_SEC 2551443 |
| Average length of one moon cycle in seconds (about 29.53 days). | |
| #define | MOON_EPOCH_UTC 947182440 |
| A known new moon to count from: 2000-01-06 18:14 UTC. | |
| #define | TIDE_PERIOD_MIN 745 |
| The lunar semidiurnal period, 12h 25m. Two of these make one tidal day. | |
| #define | TIMEBAND_DAY_MINUTES 1440 |
| Minutes in a day, the modulus every wrap here is taken over. | |
| #define | STEP_HOURS_PER_DAY 24 |
| #define | LAYOUT_ROLE_DAY ROLE_DAY |
| #define | LAYOUT_ROLE_NIGHT ROLE_NIGHT |
| #define | LAYOUT_ROLE_QUIET ROLE_QUIET |
| #define | LAYOUT_ROLE_COUNT ROLE_COUNT |
| #define | LAYOUT_INT_MAX 9999 |
| The biggest number a layout field holds. Nothing the builder writes comes close. | |
| #define | WEATHER_GROUP_CURRENT (1u << 0) |
| The current temperature and sky arrived. | |
| #define | WEATHER_GROUP_EXTRA (1u << 1) |
| At least one of the extras (humidity, wind, direction, sunrise, sunset) arrived. | |
| #define | WEATHER_GROUP_FORECAST (1u << 2) |
| At least one of today's forecast readings (UV, high, low, rain chance) arrived. | |
| #define | WEATHER_GROUP_AIR (1u << 3) |
| At least one of the air readings (feels-like, pressure, dew point) arrived. | |
Typedefs | |
| typedef void(*) | CallbackListFn(void) |
| One callback in a list. | |
| typedef Role | LayoutRole |
Enumerations | |
| enum | NightSchedMode { NIGHT_SCHED_OFF = 0 , NIGHT_SCHED_SOLAR , NIGHT_SCHED_FIXED , NIGHT_SCHED_COUNT } |
| What the schedule is following. The caller's own enum should line up with these. More... | |
| enum | Role { ROLE_DAY = 0 , ROLE_NIGHT , ROLE_QUIET , ROLE_COUNT } |
| Which of the three is showing. The caller's own storage should line up with these. More... | |
| enum | WindUnit { WIND_UNIT_KMH = 0 , WIND_UNIT_MPH , WIND_UNIT_KTS , WIND_UNIT_MS , WIND_UNIT_COUNT } |
| Which unit a wind speed reads out in. More... | |
Functions | |
| int32_t | astro_jd_centi (time_t utc) |
| The Julian Date multiplied by 100, so the whole part is the day and the last two digits are hundredths. Kept scaled to stay in plain 32-bit integers. | |
| int | beats_from_ms (int32_t ms_into_bmt_day) |
| Calculates swatch internet time in .beats (0..999) for a given ms. | |
| uint32_t | ms_until_next_beat (int32_t ms_into_bmt_day) |
| Calculates milliseconds until the next .beats boundary. | |
| int32_t | beats_ms_from_hms (int hour, int minute, int second, uint16_t ms) |
| Milliseconds into the Biel Mean Time day, from a UTC wall clock. | |
| bool | beats_has_token (const char *format) |
| Whether a date format asks for a .beats reading. | |
| void | beats_expand_token (char *text, int beats) |
| Overwrite every BEATS_TOKEN in a string with a three digit .beats reading. | |
| int | date_iso_week (int year, int yday, int wday) |
| The ISO 8601 week number, which always counts weeks from Monday. | |
| int | date_iso_week_year (int year, int yday, int wday) |
| The ISO 8601 year the week number belongs to, which is not always the calendar year. | |
| int | date_iso_weeks_in_year (int year) |
| How many ISO 8601 weeks a year holds, either 52 or 53. | |
| int | date_day_of_year (int yday) |
| Which day of the year it is, counting January 1st as day 1. | |
| int | date_days_left_in_year (int year, int yday) |
| How many days are left before the year ends, so December 31st reads 0. | |
| int | date_days_in_month (int year, int mon0) |
| How many days a month has, with February getting its leap day. | |
| int | date_first_wday (int wday, int mday) |
| The weekday the 1st of the month lands on, walked back from today's weekday. | |
| void | duration_hm (char *out, size_t n, int minutes) |
| Format minutes as a clock-style "H:MM", e.g. 445 -> "7:25". | |
| void | duration_hm_compact (char *out, size_t n, int minutes) |
| Format minutes as "Xh Ym", dropping the hours once it is under one ("45m"). | |
| time_t | hour_latch_start (time_t now, int tm_min, int tm_sec) |
| When the local hour holding a moment began, as seconds since the epoch. | |
| bool | hour_latch_take (HourLatch *latch, int tick_min, time_t start) |
| Whether a tick should buzz the hour, and if so, marks the hour as buzzed. | |
| void | hour_latch_seed (HourLatch *latch, time_t start) |
| Marks an hour as buzzed without buzzing it. | |
| int32_t | moon_age_sec (time_t utc) |
| How far into the current moon cycle we are, in seconds. | |
| int | moon_glyph_index (time_t utc, int count) |
Picks one of count evenly spaced phase icons. It wraps back round at the end. | |
| int | moon_illumination_pct (time_t utc) |
| How lit up the moon looks, from 0 to 100. This is a rough straight-line guess, so it reads 0 at new moon and 100 at full. | |
| const char * | moon_phase_name (time_t utc) |
| Short name for the current phase (one of the eight main phases). | |
| int | moon_days_to_phase (time_t utc, bool to_full) |
| How many days until the next full or new moon, rounded to the nearest whole day. | |
| bool | clock_window_contains (int start, int end, int now) |
| Whether now falls inside a window that may run past midnight. | |
| bool | night_schedule_active (int mode, int now, int rise, int set, int fixed_start, int fixed_end, bool have_night) |
| Whether the night window is open, whichever way the schedule is set. | |
| int | rotate_index (int year, int yday, int hour, int minute, int interval_min, int count) |
| Which of count is up now, advancing by one every interval_min minutes and wrapping round at the end. | |
| int | solar_day_progress (int rise, int set, int now) |
| How far through the daylight it is, from 0 at sunrise to 100 at sunset. | |
| int | solar_night_progress (int rise, int set, int now) |
| How far through the night it is, from 0 at sunset to 100 at the next sunrise. | |
| int | solar_next_event (int rise, int set, int now, bool *is_sunrise) |
| Minutes until the next sun event, and which one it is. | |
| int | tide_level (int32_t minutes) |
| How far in the tide is, from 0 at dead low to 100 at high water. | |
| bool | tide_rising (int32_t minutes) |
| Whether the tide is on its way in. | |
| TimeBand | timeband_full_day (void) |
| A window running midnight to midnight. | |
| TimeBand | timeband_rolling (int now_min, int span_min, int lead_min) |
| A window that puts a given moment a fixed way into it. | |
| TimeBand | timeband_from_hour (int base_hour, int span_min) |
| A window starting at the top of a given hour. | |
| int | timeband_offset (TimeBand band, int minute_of_day) |
| How far into the window a minute of the day falls. | |
| int | timeband_pos (TimeBand band, int length, int minute_of_day) |
| Where a minute of the day lands along an axis of a given length. | |
| int | timeband_pos_offset (TimeBand band, int length, int offset_min) |
| The same mapping for a value already measured from the window's start. | |
| bool | timeband_clip (TimeBand band, time_t window_epoch, time_t start, time_t end, TimeBandSpan *out) |
| Clip an absolute span onto the window. | |
| int | timeband_clip_daily (TimeBand band, int from_min, int to_min, TimeBandSpan *out, int max_out) |
| Clip a daily span, one that repeats every day like the daylight, onto the window. | |
| time_t | timeband_window_epoch (TimeBand band, time_t now, int now_min) |
| The epoch the window's first minute sits at. | |
| const char * | weekday_short (int wday) |
| The two-letter short name for a weekday, indexed like tm_wday and the phone's base_weekday (0 = Sunday through 6 = Saturday). | |
| bool | zone_setting_is_set (const char *value) |
| Whether the setting holds a zone at all. | |
| int16_t | zone_setting_offset (const char *value) |
| How many minutes the zone is ahead of UTC, negative for one behind. | |
| const char * | zone_setting_label (const char *value) |
| The place's name, everything after the first comma. | |
| int | minute_window_first_slot (time_t first_min, time_t end_min, int minutes) |
| Where the first of a run of back to back minute records lands in a window. | |
| int | step_hours_settled (int cur_hour, int cur_min) |
| How many whole hours have settled, meaning they can never gain another step. | |
| static int16_t | read_i16_le (const uint8_t *p) |
| Reads a little-endian signed 16-bit value out of a byte pair. | |
| static int32_t | read_i32_le (const uint8_t *p) |
| Reads a little-endian signed 32-bit value out of four bytes. | |
| bool | callback_list_add (CallbackList *list, CallbackListFn cb) |
| Adds a callback to the end of the list. Adding one that is already there does nothing. | |
| void | callback_list_fire (const CallbackList *list) |
| Runs every callback in the order it was added. | |
| LayoutRole | layout_role_pick (bool quiet_on, bool quiet_set, bool night_on, bool night_set) |
| Which layout wins. Forwards to role_pick. | |
| int | layout_parse_int (const char **cursor) |
| Reads a run of digits and moves the cursor past them. | |
| bool | layout_has_any_block (const char *layout, int type_count) |
| Whether a layout string holds at least one placeable block. | |
| int | pct_of (int value, int goal) |
| How far along a goal is, from 0 to 100. | |
| int | clamp_int (int value, int lo, int hi) |
| Pin a value into a range, so it lands on the nearer end when it falls outside. | |
| int | segment_width (int total, int gap, int count) |
| The width of one cell when a strip is carved into evenly spaced segments. | |
| int | fraction_px (int total, int num, int den) |
| A fraction of a length in pixels, e.g. how far along a bar a moment sits. | |
| int | segments_filled (int level, int segments) |
| How many cells of a gauge a percentage lights, rounding up so any charge lights one. | |
| int | plot_y (int y0, int height, int lo, int hi, int value) |
| Map a reading to its pixel row in a plot, with the low end at the bottom. | |
| int | series_range (const uint8_t *samples, int count, uint8_t no_sample, int *lo, int *hi, int *last) |
| Walk a series of samples for its low, high, and most recent reading. | |
| int | series_max_u16 (const uint16_t *values, int count) |
| The largest value in a series, for scaling a bar strip against its busiest slot. | |
| Role | role_pick (bool quiet_on, bool quiet_set, bool night_on, bool night_set) |
| Which role wins, given what is firing and what has something behind it. | |
| static void | cstring_fit (char *dst, const char *src, size_t size) |
| Copy a string into a fixed buffer, keeping only what fits and always terminating it. | |
| static bool | cstring_fit_same (const char *current, const char *value, size_t size) |
Whether copying value into a buffer would leave it reading exactly as it does now. | |
| void | number_group (char *buffer, size_t size, int value) |
| Format an integer with apostrophe thousands separators (e.g. 20358 -> "20'358"). | |
| void | fmt_int_or_dash (char *buffer, size_t size, int value, const char *fmt) |
| Format an integer, or "--" when there is no reading yet. | |
| void | fmt_hundredths (char *buffer, size_t size, int value) |
| Format hundredths as a two-decimal number, e.g. 26174 -> "261.74". | |
| void | fmt_pct_signed (char *buffer, size_t size, int value) |
| Format hundredths as a signed two-decimal percent, e.g. 125 -> "+1.25%". | |
| void | copy_bounded (char *dst, uint8_t cap, const uint8_t *src, uint8_t len) |
| Copy bytes into a fixed buffer, taking what fits and terminating it. | |
| bool | cstring_is_clean (const char *s, uint16_t size) |
| Whether a byte range holds a string worth keeping. | |
| bool | cstring_setting_is_clean (const char *s, uint16_t size, const char *default_str) |
| Whether a saved text setting reads as one, where an empty setting can be the real value. | |
| void | text_to_upper (char *s) |
| Uppercase an ascii string in place. | |
| const char * | distance_unit (bool miles) |
| Unit label for the current distance mode ("MI" or "KM"). | |
| void | distance_format_value (char *buffer, size_t size, int meters, bool miles) |
| Format meters as "N.N" (rounded to tenth), no unit suffix. | |
| void | distance_format (char *buffer, size_t size, int meters, bool miles) |
| Format meters as "N.N MI" or "N.N KM" (rounded to tenth). | |
| int | wind_from_kmh (int kmh, WindUnit unit) |
| Convert a km/h wind speed into the chosen unit. | |
| const char * | wind_unit_label (WindUnit unit) |
| The short label for a wind unit. | |
| uint8_t | forecast_hours_past (int32_t seconds_into_strip, uint8_t step_hours, uint8_t count) |
| How many of an hourly strip's columns are over. | |
| uint8_t | forecast_days_past (int days_since_first, uint8_t count) |
| How many of a daily strip's columns are days before today. | |
| bool | weather_reading_apply (WeatherState *state, const WeatherMessage *msg, const WeatherClock *clock) |
| Put a message's readings into the kept weather. | |
| void | weather_reading_convert (WeatherState *state, bool to_fahrenheit) |
| Convert every temperature in the kept weather to the other unit. | |
| int | wind_bearing (const char *dir) |
| The bearing a 16-point compass abbreviation stands for. | |
| int | wind_lean (int bearing) |
| The east-west component of a wind, as a signed proportion. | |
| void | wx_label_short (char *out, size_t n, const char *condition) |
| Writes the short word for a condition token, without its "_NIGHT" suffix. | |
| bool | calendar_wire_decode (const uint8_t *buf, uint16_t len, CalendarStrip *out) |
| Unpacks an agenda off the wire. | |
| bool | coords_look_real (const char *lat, const char *lon) |
| Whether a pair of coordinates is a place rather than the phone shrugging. | |
| bool | stock_wire_decode (const uint8_t *buf, uint16_t len, StockStrip *out) |
| Unpacks a watchlist off the wire. | |
| bool | weather_hourly_decode (const uint8_t *buf, uint16_t len, WeatherHourly *out) |
| Unpacks an hourly forecast off the wire. | |
| bool | weather_daily_decode (const uint8_t *buf, uint16_t len, WeatherDaily *out) |
| Unpacks a 7-day forecast off the wire. | |
| static int32_t | wire_int_or (bool is_signed, uint16_t length, const uint8_t *value, int32_t fallback) |
Reads a little-endian integer of exactly length bytes. | |
| static bool | wire_cstring_terminated (const char *s, uint16_t length) |
Whether a string of length bytes carries its terminator inside itself. | |
Pure maths, clock, text, and unit helpers that need no watch SDK.
Needing no SDK is what lets them be tested off the watch. Think .beats time, moon phase, weekday names, number formatting, and unit conversions.
| #define LAYOUT_ROLE_COUNT ROLE_COUNT |
| #define LAYOUT_ROLE_DAY ROLE_DAY |
| #define LAYOUT_ROLE_NIGHT ROLE_NIGHT |
| #define LAYOUT_ROLE_QUIET ROLE_QUIET |
| #define STEP_HOURS_PER_DAY 24 |
How many hourly buckets a day holds.
| typedef Role LayoutRole |
| enum NightSchedMode |
| enum Role |
| enum WindUnit |
Which unit a wind speed reads out in.
KMH is zero so a raw setting byte maps straight across and no unsigned range check ever compares below zero.
| Enumerator | |
|---|---|
| WIND_UNIT_KMH | kilometres per hour |
| WIND_UNIT_MPH | miles per hour |
| WIND_UNIT_KTS | knots |
| WIND_UNIT_MS | metres per second |
| WIND_UNIT_COUNT | how many units there are, not a unit itself |
| int32_t astro_jd_centi | ( | time_t | utc | ) |
The Julian Date multiplied by 100, so the whole part is the day and the last two digits are hundredths. Kept scaled to stay in plain 32-bit integers.
| utc | The time to read, as a UTC timestamp. |
| void beats_expand_token | ( | char * | text, |
| int | beats ) |
Overwrite every BEATS_TOKEN in a string with a three digit .beats reading.
Works in place because the token and the reading are the same width, so the string neither grows nor needs its tail shifted. A reading outside 0 to 999 is clamped rather than written, which is what keeps that width promise true.
| text | The string to fill in, NUL terminated. Left alone if NULL or tokenless. |
| beats | The reading to write, 0 to 999. |
| int beats_from_ms | ( | int32_t | ms_into_bmt_day | ) |
Calculates swatch internet time in .beats (0..999) for a given ms.
| ms_into_bmt_day | Milliseconds elapsed since Biel Mean Time (UTC+1) midnight. |
| bool beats_has_token | ( | const char * | format | ) |
Whether a date format asks for a .beats reading.
The face asks this to decide whether to run the .beats ticker. A beat is 86.4 seconds and the date line otherwise redraws on the minute, so without the ticker the reading sits stale and reports every rollover up to a minute late.
| format | The date format string, or NULL. |
| int32_t beats_ms_from_hms | ( | int | hour, |
| int | minute, | ||
| int | second, | ||
| uint16_t | ms ) |
Milliseconds into the Biel Mean Time day, from a UTC wall clock.
Takes the clock already broken apart rather than a time_t, because breaking one apart means gmtime, and on the watch gmtime and struct tm belong to the SDK rather than to time.h. Reaching for either here would drag the whole SDK into a file whose point is not needing it. The caller holds the clock and this holds the sum.
The two above want ms rather than seconds because a beat boundary falls mid-second, so flooring to whole seconds reads a beat behind at exactly the moment a timer fires to redraw.
| hour | The UTC hour (0 to 23). |
| minute | The UTC minute (0 to 59). |
| second | The UTC second (0 to 59). |
| ms | The milliseconds within that second. |
| bool calendar_wire_decode | ( | const uint8_t * | buf, |
| uint16_t | len, | ||
| CalendarStrip * | out ) |
Unpacks an agenda off the wire.
Layout is [count] then per event [start int32 LE][end int32 LE][flags bit0=allDay][titleLen] [title bytes][locLen][loc bytes]. A count past what the strip holds is pinned to it rather than walking off the end.
Nothing is written to out until the whole run reads clean, so a message that stops halfway leaves the caller's last good agenda alone rather than half replacing it.
| buf | The raw wire bytes. | |
| len | How many bytes there are. | |
| [out] | out | Receives the agenda. Untouched unless this returns true. |
| bool callback_list_add | ( | CallbackList * | list, |
| CallbackListFn | cb ) |
Adds a callback to the end of the list. Adding one that is already there does nothing.
| list | The list. |
| cb | The callback. NULL is ignored. |
cb was dropped, so the owner can say so. | void callback_list_fire | ( | const CallbackList * | list | ) |
Runs every callback in the order it was added.
| list | The list. |
| int clamp_int | ( | int | value, |
| int | lo, | ||
| int | hi ) |
Pin a value into a range, so it lands on the nearer end when it falls outside.
| value | The value to pin. |
| lo | The low end, returned when the value is below it. |
| hi | The high end, returned when the value is above it. |
| bool clock_window_contains | ( | int | start, |
| int | end, | ||
| int | now ) |
Whether now falls inside a window that may run past midnight.
The start is inclusive and the end exclusive, so two windows that meet at the same minute never both claim it. A window that starts and ends at the same minute is empty rather than eternal, which is the reading that does not surprise anyone who set both dials the same by accident.
| start | First minute inside the window, 0 to 1439, or -1 for no reading. |
| end | First minute past it, same range. |
| now | Minutes past midnight. |
| bool coords_look_real | ( | const char * | lat, |
| const char * | lon ) |
Whether a pair of coordinates is a place rather than the phone shrugging.
The phone sends coordinates as text and says "no fix" by sending something that is not one: an empty string, or a word like "NO LOCK". A coordinate always carries digits and those never do, which is the whole of the test.
Both halves have to hold up. Half a fix is not half a place. It is not a place, and keeping one is how a longitude goes missing and stays missing.
| lat | The latitude as the phone sent it. |
| lon | The longitude as the phone sent it. |
| void copy_bounded | ( | char * | dst, |
| uint8_t | cap, | ||
| const uint8_t * | src, | ||
| uint8_t | len ) |
Copy bytes into a fixed buffer, taking what fits and terminating it.
For the length-prefixed text the phone sends, where the length is the phone's word and the room is ours. What does not fit is dropped rather than written past the end.
| [out] | dst | Where to write. Ends terminated whenever cap is at least 1. |
| cap | How much room dst has, terminator included. A cap of 0 has no room even for the terminator, so dst is left untouched and not terminated. | |
| src | The bytes to copy. | |
| len | How many bytes there are. |
|
inlinestatic |
Copy a string into a fixed buffer, keeping only what fits and always terminating it.
The cut counts bytes, so a character that takes more than one byte can be split at it. The fonts carry only the characters a face shows, which a character past ASCII is not, so it draws as a box whether it is cut or whole, and walking back to a character boundary would cost bytes for nothing.
| dst | The buffer to write into. |
| src | The string to copy, or NULL to empty the buffer. |
| size | The buffer's size, terminator included. |
|
inlinestatic |
Whether copying value into a buffer would leave it reading exactly as it does now.
The copy keeps only what fits, so the incoming string is measured the same way. Comparing it in full instead would call a value longer than the buffer a change every single time, which for a settings field means re-reacting to a setting nobody touched.
| current | What the buffer holds now. |
| value | The string that would be copied in. Must not be NULL. |
| size | The buffer's size, terminator included. |
| bool cstring_is_clean | ( | const char * | s, |
| uint16_t | size ) |
Whether a byte range holds a string worth keeping.
Worth keeping means it ends inside its own room, it says something, and it carries no control bytes. Everything from 0x20 up counts as text, UTF-8 included, so a place name spelled with an umlaut is text and not damage. Getting that wrong is how a saved city turns back into the default one on the next boot.
| s | The bytes to look at. |
| size | How much room they have. |
| bool cstring_setting_is_clean | ( | const char * | s, |
| uint16_t | size, | ||
| const char * | default_str ) |
Whether a saved text setting reads as one, where an empty setting can be the real value.
A setting whose default is empty, such as a picker whose "None" is "", holds nothing on purpose, so empty is a value for it and not damage. Any other setting keeps the cstring_is_clean rule, since an empty one there is what a wiped blob reads like.
| s | The bytes to look at. |
| size | How much room they have. |
| default_str | The setting's default, or NULL for none. |
| int date_day_of_year | ( | int | yday | ) |
Which day of the year it is, counting January 1st as day 1.
| yday | The day of the year counting January 1st as 0 (like tm_yday). |
| int date_days_in_month | ( | int | year, |
| int | mon0 ) |
How many days a month has, with February getting its leap day.
| year | The full year (2026, not 126). |
| mon0 | The month indexed like tm_mon (0 January to 11 December). |
| int date_days_left_in_year | ( | int | year, |
| int | yday ) |
How many days are left before the year ends, so December 31st reads 0.
| year | The full year (2026, not 126). |
| yday | The day of the year counting January 1st as 0 (like tm_yday). |
| int date_first_wday | ( | int | wday, |
| int | mday ) |
The weekday the 1st of the month lands on, walked back from today's weekday.
| wday | Today's weekday, 0 Sunday to 6 Saturday. |
| mday | Today's day of the month, 1 to 31. |
| int date_iso_week | ( | int | year, |
| int | yday, | ||
| int | wday ) |
The ISO 8601 week number, which always counts weeks from Monday.
A week near a year boundary can belong to the neighbouring year, so the number this returns is not always counted within the year you passed in. Pair it with date_iso_week_year to find out which year it belongs to, and total it against that year rather than this one.
| year | The full year (2026, not 126). |
| yday | The day of the year counting January 1st as 0 (like tm_yday). |
| wday | The weekday, 0 Sunday to 6 Saturday. |
| int date_iso_week_year | ( | int | year, |
| int | yday, | ||
| int | wday ) |
The ISO 8601 year the week number belongs to, which is not always the calendar year.
Early January can fall in the previous ISO year and late December in the next one. Feeding this to date_iso_weeks_in_year gives the total that matches what date_iso_week returned, so a "week of total" readout can't end up with a number bigger than its own total.
| year | The full year (2026, not 126). |
| yday | The day of the year counting January 1st as 0 (like tm_yday). |
| wday | The weekday, 0 Sunday to 6 Saturday. |
| int date_iso_weeks_in_year | ( | int | year | ) |
How many ISO 8601 weeks a year holds, either 52 or 53.
| year | The full year (2026, not 126). |
| void distance_format | ( | char * | buffer, |
| size_t | size, | ||
| int | meters, | ||
| bool | miles ) |
Format meters as "N.N MI" or "N.N KM" (rounded to tenth).
| [out] | buffer | Output buffer. |
| size | Buffer size. | |
| meters | Distance in meters. | |
| miles | Format as miles if true, otherwise km. |
| void distance_format_value | ( | char * | buffer, |
| size_t | size, | ||
| int | meters, | ||
| bool | miles ) |
Format meters as "N.N" (rounded to tenth), no unit suffix.
| [out] | buffer | Output buffer. |
| size | Buffer size. | |
| meters | Distance in meters. | |
| miles | Format as miles if true, otherwise km. |
| const char * distance_unit | ( | bool | miles | ) |
Unit label for the current distance mode ("MI" or "KM").
| miles | Miles if true, otherwise km. |
| void duration_hm | ( | char * | out, |
| size_t | n, | ||
| int | minutes ) |
Format minutes as a clock-style "H:MM", e.g. 445 -> "7:25".
The minutes are zero-padded, so seven hours and five minutes reads "7:05" and not "7:5". A negative count is nothing and reads "0:00".
| out | Output buffer. |
| n | Buffer size. |
| minutes | The duration in minutes. |
| void duration_hm_compact | ( | char * | out, |
| size_t | n, | ||
| int | minutes ) |
Format minutes as "Xh Ym", dropping the hours once it is under one ("45m").
For a countdown, where the hours are only worth showing once there is at least one. A negative count is nothing and reads "0m".
| out | Output buffer. |
| n | Buffer size. |
| minutes | The duration in minutes. |
| void fmt_hundredths | ( | char * | buffer, |
| size_t | size, | ||
| int | value ) |
Format hundredths as a two-decimal number, e.g. 26174 -> "261.74".
Prices and the like ride the wire as whole hundredths so they never touch a float. The sign is written out front rather than left to the whole part, which is what makes -50 read as "-0.50" instead of losing its minus to a whole part of zero.
| [out] | buffer | Output buffer. |
| size | Buffer size. | |
| value | The number times 100. |
| void fmt_int_or_dash | ( | char * | buffer, |
| size_t | size, | ||
| int | value, | ||
| const char * | fmt ) |
Format an integer, or "--" when there is no reading yet.
A negative value is the no-data marker the readouts share, so this is the one place that turns "I have nothing" into something to draw. The format takes exactly one int, so "%d" or "%d%%".
| [out] | buffer | Output buffer. |
| size | Buffer size. | |
| value | The reading, or a negative number for no data yet. | |
| fmt | The printf format applied when the value is there. |
| void fmt_pct_signed | ( | char * | buffer, |
| size_t | size, | ||
| int | value ) |
Format hundredths as a signed two-decimal percent, e.g. 125 -> "+1.25%".
A gain takes a plus, a loss a minus, and flat takes neither. Same reason as fmt_hundredths for writing the sign out front: a change under one percent has a whole part of zero and would lose it otherwise.
| [out] | buffer | Output buffer. |
| size | Buffer size. | |
| value | The percent times 100, signed. |
| uint8_t forecast_days_past | ( | int | days_since_first, |
| uint8_t | count ) |
How many of a daily strip's columns are days before today.
| days_since_first | Whole days from the strip's first day to today. Zero or less means the strip starts today or later. |
| count | How many columns the strip holds. |
count. | uint8_t forecast_hours_past | ( | int32_t | seconds_into_strip, |
| uint8_t | step_hours, | ||
| uint8_t | count ) |
How many of an hourly strip's columns are over.
A column is over once its whole step has gone by, so the column holding the current hour stays.
| seconds_into_strip | Seconds from the start of the first column to now. Zero or less means the strip has not started yet. |
| step_hours | Hours between columns. |
| count | How many columns the strip holds. |
count. | int fraction_px | ( | int | total, |
| int | num, | ||
| int | den ) |
A fraction of a length in pixels, e.g. how far along a bar a moment sits.
| total | The full length. |
| num | The numerator of the fraction. |
| den | The denominator of the fraction. |
| void hour_latch_seed | ( | HourLatch * | latch, |
| time_t | start ) |
Marks an hour as buzzed without buzzing it.
| latch | The latch to update. |
| start | When the hour began, from hour_latch_start. |
| time_t hour_latch_start | ( | time_t | now, |
| int | tm_min, | ||
| int | tm_sec ) |
When the local hour holding a moment began, as seconds since the epoch.
The minute and second have to come from breaking apart the same reading as now. Taking them from an older tick gives one hour two starts whenever a second turns over between the two reads, and the hour buzzes twice.
| now | The moment, as seconds since the epoch. |
| tm_min | The local minute of now. |
| tm_sec | The local second of now. |
| bool hour_latch_take | ( | HourLatch * | latch, |
| int | tick_min, | ||
| time_t | start ) |
Whether a tick should buzz the hour, and if so, marks the hour as buzzed.
| latch | The latch to check and update. |
| tick_min | The minute of the tick that is asking. Only minute 0 can buzz. |
| start | When the current hour began, from hour_latch_start. |
| bool layout_has_any_block | ( | const char * | layout, |
| int | type_count ) |
Whether a layout string holds at least one placeable block.
One test covers the ways a layout can be nothing: the "0" marker a cleared grid is sent as, an empty string, and whatever a corrupt blob left behind. A record naming a module the catalogue does not have is not placeable either, so it does not count.
| layout | The wire string, or NULL. |
| type_count | How many module numbers the caller's catalogue has, so anything at or past it is junk. |
| int layout_parse_int | ( | const char ** | cursor | ) |
Reads a run of digits and moves the cursor past them.
A number past LAYOUT_INT_MAX comes back as -1 rather than overflowing, since only a corrupt string holds one. Its digits are still skipped, so the cursor lands on the next field either way.
| cursor | The cursor, moved past the digits. |
| LayoutRole layout_role_pick | ( | bool | quiet_on, |
| bool | quiet_set, | ||
| bool | night_on, | ||
| bool | night_set ) |
Which layout wins. Forwards to role_pick.
| quiet_on | True while Quiet Time is on. |
| quiet_set | True when a layout is assigned to Quiet Time. |
| night_on | True while the night schedule says it is night. |
| night_set | True when a layout is assigned to night. |
| int minute_window_first_slot | ( | time_t | first_min, |
| time_t | end_min, | ||
| int | minutes ) |
Where the first of a run of back to back minute records lands in a window.
The window's last slot holds end_min and each slot before it holds the minute before. A record older than the window lands below zero, one newer than its end lands past the last slot, and the caller skips both.
| first_min | The minute the first record belongs to, as minutes since the epoch. |
| end_min | The minute the window's last slot holds, the same way. |
| minutes | How many slots the window has. |
| int32_t moon_age_sec | ( | time_t | utc | ) |
How far into the current moon cycle we are, in seconds.
| utc | The time to read, as a UTC timestamp. |
| int moon_days_to_phase | ( | time_t | utc, |
| bool | to_full ) |
How many days until the next full or new moon, rounded to the nearest whole day.
Within half a day of the moon, before or after, it counts as now.
| utc | The time to read, as a UTC timestamp. |
| to_full | True counts to the next full moon, false to the next new moon. |
| int moon_glyph_index | ( | time_t | utc, |
| int | count ) |
Picks one of count evenly spaced phase icons. It wraps back round at the end.
| utc | The time to read, as a UTC timestamp. |
| count | How many phase icons there are. |
count is not positive). | int moon_illumination_pct | ( | time_t | utc | ) |
How lit up the moon looks, from 0 to 100. This is a rough straight-line guess, so it reads 0 at new moon and 100 at full.
| utc | The time to read, as a UTC timestamp. |
| const char * moon_phase_name | ( | time_t | utc | ) |
Short name for the current phase (one of the eight main phases).
| utc | The time to read, as a UTC timestamp. |
| uint32_t ms_until_next_beat | ( | int32_t | ms_into_bmt_day | ) |
Calculates milliseconds until the next .beats boundary.
A single beat is exactly 86,400 milliseconds. This is useful for scheduling timers to trigger exactly when the beat rolls over.
| ms_into_bmt_day | Milliseconds elapsed since Biel Mean Time (UTC+1) midnight. |
| bool night_schedule_active | ( | int | mode, |
| int | now, | ||
| int | rise, | ||
| int | set, | ||
| int | fixed_start, | ||
| int | fixed_end, | ||
| bool | have_night ) |
Whether the night window is open, whichever way the schedule is set.
Following the sun needs both a sunrise and a sunset to work from. When either is missing this falls back to the fixed pair rather than giving up, so a watch that has never been told where it is still does something sensible, and the two dials the user set earn their keep twice.
| mode | A NightSchedMode. Anything out of range reads as off. |
| now | Minutes past midnight. |
| rise | Sunrise, or -1 for no reading. |
| set | Sunset, same. |
| fixed_start | The user's own start, used by the fixed mode and as the solar fallback. |
| fixed_end | And their end. |
| have_night | True when there is actually a night look to switch to. |
| void number_group | ( | char * | buffer, |
| size_t | size, | ||
| int | value ) |
Format an integer with apostrophe thousands separators (e.g. 20358 -> "20'358").
Negative values keep their leading sign. The Swiss-style apostrophe keeps big counts readable on the small display.
| [out] | buffer | Output buffer. |
| size | Buffer size. | |
| value | The value to format. |
| int pct_of | ( | int | value, |
| int | goal ) |
How far along a goal is, from 0 to 100.
Caps at 100 so a beaten goal fills a bar rather than overflowing it, and answers 0 rather than dividing by a goal of zero.
| value | How much is done so far. |
| goal | What is being aimed at. |
| int plot_y | ( | int | y0, |
| int | height, | ||
| int | lo, | ||
| int | hi, | ||
| int | value ) |
Map a reading to its pixel row in a plot, with the low end at the bottom.
The window runs from lo at the bottom row to hi at the top, so a bigger reading sits higher up the panel. A reading outside the window is pinned to the nearer edge first, so it never lands on a row outside the plot area.
| y0 | The top row of the plot area. |
| height | The plot area's height in rows. |
| lo | The value at the bottom of the window. |
| hi | The value at the top of the window. |
| value | The reading to place. |
|
inlinestatic |
Reads a little-endian signed 16-bit value out of a byte pair.
| p | The first of the two bytes. |
|
inlinestatic |
Reads a little-endian signed 32-bit value out of four bytes.
| p | The first of the four bytes. |
| Role role_pick | ( | bool | quiet_on, |
| bool | quiet_set, | ||
| bool | night_on, | ||
| bool | night_set ) |
Which role wins, given what is firing and what has something behind it.
Quiet Time sits above the night schedule on purpose. Someone who has set both is saying they want a quieter screen while the watch is quiet, and that holds whether it happens to be dark out or not.
A trigger with nothing assigned is skipped rather than honoured, so the answer walks down to the next one that has something to show and lands on the day role if nothing else does. That is what lets someone use one of these without filling in the other.
| quiet_on | True while Quiet Time is on. |
| quiet_set | True when something is assigned to Quiet Time. |
| night_on | True while the night schedule says it is night. |
| night_set | True when something is assigned to night. |
| int rotate_index | ( | int | year, |
| int | yday, | ||
| int | hour, | ||
| int | minute, | ||
| int | interval_min, | ||
| int | count ) |
Which of count is up now, advancing by one every interval_min minutes and wrapping round at the end.
The answer holds steady through a slot and steps to the next when the slot turns over, so a screen drawn from it only changes on a boundary. It is 0 for a count of one, and for an interval or a count that is not positive, which is the safe nothing-to-rotate answer.
It counts the year as a round 366 days, so the one boundary at a non-leap new year jumps by more than a single step and can, for a count that divides the jump, land on the same one twice. For a shuffle that one ragged boundary a year does not matter.
The time comes in as the same fields a struct tm carries, so the caller hands them straight from its broken-apart clock.
| year | Years since 1900, as tm_year. |
| yday | Days into the year, 0 to 365, as tm_yday. |
| hour | The hour, 0 to 23, as tm_hour. |
| minute | The minute, 0 to 59, as tm_min. |
| interval_min | How many minutes each one is shown for. |
| count | How many there are to rotate through. |
| int segment_width | ( | int | total, |
| int | gap, | ||
| int | count ) |
The width of one cell when a strip is carved into evenly spaced segments.
The gaps sit between the cells, so there is one fewer gap than there are cells. The division truncates, which leaves a few pixels of remainder for the caller to centre or absorb.
| total | The strip's full width. |
| gap | The space between two cells. |
| count | How many cells there are. |
| int segments_filled | ( | int | level, |
| int | segments ) |
How many cells of a gauge a percentage lights, rounding up so any charge lights one.
The level is pinned to 0..100 first, so a stray reading cannot light more cells than there are. Rounding up means 1% still shows a cell and 100% fills them all.
| level | The fill from 0 to 100. |
| segments | How many cells the gauge has. |
| int series_max_u16 | ( | const uint16_t * | values, |
| int | count ) |
The largest value in a series, for scaling a bar strip against its busiest slot.
| values | The readings. |
| count | How many there are. |
| int series_range | ( | const uint8_t * | samples, |
| int | count, | ||
| uint8_t | no_sample, | ||
| int * | lo, | ||
| int * | hi, | ||
| int * | last ) |
Walk a series of samples for its low, high, and most recent reading.
A slot holding the no-sample value is skipped, so a gappy history still reads its real values. The outputs are filled only when there is at least one real sample. With none they are left as the caller set them, so a caller that seeds them and checks the count first cannot read a value that was never there.
| samples | The readings, oldest first so the last real one is the most recent. | |
| count | How many slots there are. | |
| no_sample | The value that marks an empty slot. | |
| [out] | lo | Receives the lowest real reading. |
| [out] | hi | Receives the highest real reading. |
| [out] | last | Receives the most recent real reading. |
| int solar_day_progress | ( | int | rise, |
| int | set, | ||
| int | now ) |
How far through the daylight it is, from 0 at sunrise to 100 at sunset.
| rise | Sunrise, minutes past midnight, or -1 for no data. |
| set | Sunset, minutes past midnight, or -1 for no data. |
| now | The clock, minutes past midnight, or -1 for no data. |
| int solar_next_event | ( | int | rise, |
| int | set, | ||
| int | now, | ||
| bool * | is_sunrise ) |
Minutes until the next sun event, and which one it is.
Sunrise while it is dark, sunset while the sun is up, and tomorrow's sunrise once it has set, wrapping midnight the same way the night progress does.
| rise | Sunrise, minutes past midnight, or -1 for no data. |
| set | Sunset, minutes past midnight, or -1 for no data. |
| now | The clock, minutes past midnight, or -1 for no data. |
| is_sunrise | Receives whether the next event is a sunrise. Untouched when there is no data. |
| int solar_night_progress | ( | int | rise, |
| int | set, | ||
| int | now ) |
How far through the night it is, from 0 at sunset to 100 at the next sunrise.
The night usually straddles midnight, so the span runs from sunset round to the next sunrise.
| rise | Sunrise, minutes past midnight, or -1 for no data. |
| set | Sunset, minutes past midnight, or -1 for no data. |
| now | The clock, minutes past midnight, or -1 for no data. |
| int step_hours_settled | ( | int | cur_hour, |
| int | cur_min ) |
How many whole hours have settled, meaning they can never gain another step.
The hour in progress never counts, nor does the hour just gone while the clock is on its first minute: the watch writes a minute's record at the top of the minute after it, below the watchface in priority, so on the rollover turn that last record is usually not there yet.
| cur_hour | The hour now, 0 to 23. |
| cur_min | The minute within that hour, 0 to 59. |
| bool stock_wire_decode | ( | const uint8_t * | buf, |
| uint16_t | len, | ||
| StockStrip * | out ) |
Unpacks a watchlist off the wire.
Layout is [count] then per slot [ok][price int32 LE cents][pct int16 LE hundredths][symLen] [sym bytes]. A count past what the strip holds is pinned to it rather than walking off the end.
Nothing is written to out until the whole run reads clean, so a message that stops halfway leaves the caller's last good watchlist alone rather than half replacing it.
| buf | The raw wire bytes. | |
| len | How many bytes there are. | |
| [out] | out | Receives the watchlist. Untouched unless this returns true. |
| void text_to_upper | ( | char * | s | ) |
Uppercase an ascii string in place.
| s | The string to uppercase. |
| int tide_level | ( | int32_t | minutes | ) |
How far in the tide is, from 0 at dead low to 100 at high water.
Eased at both ends rather than run at a constant rate, because a real tide stands almost still around the turn and moves fastest halfway through. Water creeping up the sand and then pausing is the part that reads as tidal.
| minutes | A running minute count, e.g. the epoch in minutes. Negative values are fine. |
| bool tide_rising | ( | int32_t | minutes | ) |
Whether the tide is on its way in.
| minutes | A running minute count, on the same base as tide_level. |
| bool timeband_clip | ( | TimeBand | band, |
| time_t | window_epoch, | ||
| time_t | start, | ||
| time_t | end, | ||
| TimeBandSpan * | out ) |
Clip an absolute span onto the window.
Both ends are epochs, which is what an agenda carries, and the window's own first minute is given as one too, so an event from yesterday or from next week falls outside rather than being wrapped onto today.
A span with no length still comes back a minute wide, so a moment someone pinned to their calendar still draws instead of vanishing.
| band | The window. |
| window_epoch | The epoch of the window's first minute. |
| start | The span's start. |
| end | The span's end. An end before the start is read as having no length. |
| out | Receives the clipped span. Untouched unless this returns true. |
| int timeband_clip_daily | ( | TimeBand | band, |
| int | from_min, | ||
| int | to_min, | ||
| TimeBandSpan * | out, | ||
| int | max_out ) |
Clip a daily span, one that repeats every day like the daylight, onto the window.
A window running past midnight can see the same daily span at both of its ends, which is why this hands back pieces rather than one span. A span whose end is at or before its start is read as wrapping midnight itself, so a polar winter's short daylight and a midsummer night's short darkness both work without the caller knowing which it has.
| band | The window. |
| from_min | The daily span's start, minutes past midnight, or -1 for no reading. |
| to_min | Its end, same. A -1 on either side gives no pieces. |
| out | Receives the pieces, earliest first. |
| max_out | How many out holds. Two is enough for any window of a day or less. |
| TimeBand timeband_from_hour | ( | int | base_hour, |
| int | span_min ) |
A window starting at the top of a given hour.
The hourly forecast carries its own base hour, so feeding it in here lands the strip's columns on even fractions of the axis instead of somewhere arbitrary along it.
| base_hour | The hour the window opens on, wrapped into 0..23. |
| span_min | How long it runs, pinned to 1..1440. |
| int timeband_offset | ( | TimeBand | band, |
| int | minute_of_day ) |
How far into the window a minute of the day falls.
| band | The window. |
| minute_of_day | The moment, minutes past midnight. |
| int timeband_pos | ( | TimeBand | band, |
| int | length, | ||
| int | minute_of_day ) |
Where a minute of the day lands along an axis of a given length.
| band | The window. |
| length | The axis length in whatever the caller measures it in. |
| minute_of_day | The moment, minutes past midnight. |
| int timeband_pos_offset | ( | TimeBand | band, |
| int | length, | ||
| int | offset_min ) |
The same mapping for a value already measured from the window's start.
This is the one the drawing uses, since everything clipped comes back as an offset. It takes the far end too, so a span ending exactly at the window's end reaches the end of the axis rather than stopping a unit short.
| band | The window. |
| length | The axis length. |
| offset_min | Minutes past the window's start, 0 to span_min. |
| TimeBand timeband_rolling | ( | int | now_min, |
| int | span_min, | ||
| int | lead_min ) |
A window that puts a given moment a fixed way into it.
| now_min | The moment to place, minutes past midnight. |
| span_min | How long the window runs, pinned to 1..1440. |
| lead_min | How far into it the moment sits, pinned to 0..span_min - 1. The window's last minute is the furthest in, since its far end belongs to whatever comes next. |
| time_t timeband_window_epoch | ( | TimeBand | band, |
| time_t | now, | ||
| int | now_min ) |
The epoch the window's first minute sits at.
It counts back from now rather than forward from midnight. A day the clocks change on is an hour short or long, so midnight plus the window's start would land an hour off, while the minutes between the window's start and now are the same real minutes on any day. A rolling window that crossed midnight opened yesterday, which counting back finds without being told.
A window that has not opened yet, such as a forecast strip starting at the next hour, is the one coming up later today.
The clock is handed over both ways rather than worked out here, so this needs no localtime and tests off the watch.
| band | The window. |
| now | The clock as an epoch. |
| now_min | The same moment on the wall clock, minutes past midnight. |
| bool weather_daily_decode | ( | const uint8_t * | buf, |
| uint16_t | len, | ||
| WeatherDaily * | out ) |
Unpacks a 7-day forecast off the wire.
Layout is [count][base_weekday] then per column [code][max int16 LE][min int16 LE]. A count past what the strip holds is pinned to it rather than walking off the end.
| buf | The raw wire bytes. | |
| len | How many bytes there are. | |
| [out] | out | Receives the strip. Untouched unless this returns true: everything that can turn a message away is settled before the first byte of it is written. |
| bool weather_hourly_decode | ( | const uint8_t * | buf, |
| uint16_t | len, | ||
| WeatherHourly * | out ) |
Unpacks an hourly forecast off the wire.
Layout is [count][base_hour][step_hours] then per column [code][temp int16 LE]. A count past what the strip holds is pinned to it rather than walking off the end.
| buf | The raw wire bytes. | |
| len | How many bytes there are. | |
| [out] | out | Receives the strip. Untouched unless this returns true: everything that can turn a message away is settled before the first byte of it is written. |
| bool weather_reading_apply | ( | WeatherState * | state, |
| const WeatherMessage * | msg, | ||
| const WeatherClock * | clock ) |
Put a message's readings into the kept weather.
A group that did not arrive leaves its readings alone. One that did replaces all of them, and a reading it left out becomes that reading's no-data value, -1 or WEATHER_NO_TEMP for the temperatures. The current temperature, the high and low, the feels-like, and the dew point are held to -99 to 199, and one sent as WEATHER_NO_TEMP stays no data. A failed fetch keeps the last good temperature and sky. A strip that does not read clean keeps the last good row, and a strip's temperatures are kept as they arrive until weather_reading_convert holds them to the same range.
Each strip that reads clean records where its first column starts, and the high, low, UV, and rain chance record the day they came, so the store can tell later what has gone by.
| state | The kept weather, updated in place. |
| msg | The message. |
| clock | The watch's clock as the message landed. Its time is stamped as the last sync when anything was kept. |
| void weather_reading_convert | ( | WeatherState * | state, |
| bool | to_fahrenheit ) |
Convert every temperature in the kept weather to the other unit.
Runs when the wearer switches units, so the reading in hand matches the new letter until the phone's fetch in the new unit lands. Each value rounds to the nearest degree, and a reading with no data stays that way.
| state | The kept weather, converted in place. |
| to_fahrenheit | True to go from Celsius to Fahrenheit, false for the other way. |
| const char * weekday_short | ( | int | wday | ) |
The two-letter short name for a weekday, indexed like tm_wday and the phone's base_weekday (0 = Sunday through 6 = Saturday).
| wday | The weekday, 0 (Sunday) through 6 (Saturday). |
| int wind_bearing | ( | const char * | dir | ) |
The bearing a 16-point compass abbreviation stands for.
Meteorological convention: the bearing is where the wind is coming from, so "N" is 0 and a northerly blows towards the south.
| dir | The abbreviation, e.g. "N", "ESE", "NW". Case insensitive. |
| int wind_from_kmh | ( | int | kmh, |
| WindUnit | unit ) |
Convert a km/h wind speed into the chosen unit.
Integer maths, truncated. An unknown unit falls back to km/h.
| kmh | The wind speed in km/h. |
| unit | The unit to convert into. |
| int wind_lean | ( | int | bearing | ) |
The east-west component of a wind, as a signed proportion.
Anything drawn from the side only shows the part of a wind that runs across the view: one blowing straight towards or away from the viewer has no sideways component at all, and one blowing along the view has the whole of it. Positive is eastward, which is the way a wind out of the west goes.
| bearing | Degrees, or -1 for no data. |
| const char * wind_unit_label | ( | WindUnit | unit | ) |
The short label for a wind unit.
| unit | The unit to label. |
|
inlinestatic |
Whether a string of length bytes carries its terminator inside itself.
A sender is supposed to include the terminator and nothing re-checks that it did. A string without one is not a string: reading it runs on past the end looking for a zero byte that belongs to something else, or to nothing at all.
| s | The first byte of the string. |
| length | How many bytes the string occupies, terminator included. |
|
inlinestatic |
Reads a little-endian integer of exactly length bytes.
| is_signed | Whether the value is signed. Decides only what the top bit means. |
| length | How many bytes the value occupies. 1, 2, and 4 are the widths a sender may use, and anything else is refused rather than guessed at. |
| value | The first byte of the value. |
| fallback | Returned when the width is not one a sender may use, or there is no value. |
fallback. | void wx_label_short | ( | char * | out, |
| size_t | n, | ||
| const char * | condition ) |
Writes the short word for a condition token, without its "_NIGHT" suffix.
| out | Where the word goes. |
| n | The room in out, terminator included. |
| condition | The token, such as "PCLDY_NIGHT". NULL or empty writes "UNKNOWN". |
| bool zone_setting_is_set | ( | const char * | value | ) |
Whether the setting holds a zone at all.
An empty one is no zone rather than UTC with no name, so a panel shows dashes for it rather than a clock for a place nobody picked.
| value | The setting, or NULL. |
| const char * zone_setting_label | ( | const char * | value | ) |
The place's name, everything after the first comma.
A name can carry commas of its own, as in "Paris, Ile-de-France, France", so a caller that wants only the city cuts it at the next comma itself.
| value | The setting, or NULL. |
| int16_t zone_setting_offset | ( | const char * | value | ) |
How many minutes the zone is ahead of UTC, negative for one behind.
| value | The setting, or NULL. |