Loading...
Searching...
No Matches
Stores

Weather, health, calendar, stocks, and the other readings a face shows. More...

Files

file  src/c/pebble/io/stores/calendar_store.c
 The active calendar store: holds the agenda, owns the appmessage calendar channel, and asks the phone for more whenever its turn on the face's cadence finds a poll due.
file  src/c/pebble/io/stores/calendar_store.h
 Active calendar store. It owns the appmessage calendar channel and its place on the shared cadence, so a face just hands it the rules (live / poll interval), optionally seeds it, then reads the events and subscribes for repaints. The phone data flows straight in and nobody wires it.
file  src/c/pebble/io/stores/health_store.c
 The active health store: reads the watch's health service and holds the numbers. It owns the service accessors too so it is the single point of truth for health.
file  src/c/pebble/io/stores/health_store.h
 Active health store. It subscribes to the watch's health service itself and holds the readings, so a face just hands it the rules, optionally seeds it, then reads the numbers back.
file  src/c/pebble/io/stores/location_store.c
 The active location store: holds the phone's coordinates and owns the appmessage coords channel.
file  src/c/pebble/io/stores/location_store.h
 Active location store. It owns the appmessage coords channel (the same phone geolocation the weather rides on), so a face hands it the rules, optionally seeds it, then reads lat/lon back. There's no poll timer. Coords arrive alongside weather.
file  src/c/pebble/io/stores/stock_store.c
 The active stock store: holds the quotes, owns the appmessage stock channel, and asks the phone for more whenever its turn on the face's cadence finds a poll due.
file  src/c/pebble/io/stores/stock_store.h
 Active stock store. It owns the appmessage stock channel and its place on the shared cadence, so a face just hands it the rules (live / poll interval), optionally seeds it, then reads the slots and subscribes for repaints. The phone data flows straight in and nobody wires it.
file  src/c/pebble/io/stores/store_cadence.c
 Holds the list of work the stores want run on the face's cadence.
file  src/c/pebble/io/stores/store_cadence.h
 The shared cadence the stores hang their periodic work on.
file  src/c/pebble/io/stores/store_fetch.c
 The fetch timing the polling stores share, in one copy every store links against.
file  src/c/pebble/io/stores/store_fetch.h
 The fetch timing the polling stores share: the one-shot catch-up, the cadence turn, and what an init or a reconfigure does to them.
file  src/c/pebble/io/stores/store_persist.c
 The save that skips an unchanged reading and the restore that feeds it, in one copy every store links against.
file  src/c/pebble/io/stores/store_persist.h
 Shared persist save and restore helpers for the stores.
file  src/c/pebble/io/stores/store_poll.c
 The polling decisions the weather, stock, and calendar stores share.
file  src/c/pebble/io/stores/store_poll.h
 Wall-clock deadlines for the stores that poll the phone.
file  src/c/pebble/io/stores/store_sum.c
 The checksum the stores compare before saving, in one copy every store links against.
file  src/c/pebble/io/stores/store_sum.h
 A checksum of a store's reading, so a reply that brings nothing new costs no flash write.
file  src/c/pebble/io/stores/system_store.c
 The active system store: holds the battery + bluetooth state and subscribes to the battery and connection services itself. The alarm is read through on demand.
file  src/c/pebble/io/stores/system_store.h
 Active system store: the watch's own battery, bluetooth and next-alarm state. It subscribes to the battery and connection services itself and buzzes on a bluetooth change through a policy the face installs (so the store never has to know about settings or buzzing).
file  src/c/pebble/io/stores/time_store.c
 The active time store: holds the current time and owns the tickers that update it.
file  src/c/pebble/io/stores/time_store.h
 Active time store. It owns the tickers (the minute tick, the swatch .beats AppTimer, and the hour tick) and swaps between them for the current cadence, so a face just hands it the rules and reads the time back.
file  src/c/pebble/io/stores/weather_store.c
 The active weather store: holds the readings, owns the appmessage weather channels, and asks the phone for more whenever its turn on the face's cadence finds a poll due.
file  src/c/pebble/io/stores/weather_store.h
 Active weather store. It owns the appmessage weather channels and its place on the shared cadence, so a face just hands it the rules (live / poll interval), optionally seeds it, then reads the values and subscribes for repaints. The phone data flows straight in and nobody wires it.

Data Structures

struct  CalendarConfig
 The rules a face hands the store, built from its own settings so the store names no SETTING_*. More...
struct  CalendarSeed
 Optional prefill: shown until the first real reading lands, or pinned when live = false. More...
struct  HealthConfig
 The rules a face hands the store. More...
struct  HealthSeed
 Optional prefill, or pinned readings when live = false. More...
struct  LocationConfig
 The rules a face hands the store. More...
struct  LocationSeed
 Optional prefill, or pinned coords when live = false. On a live store a seed takes the place of restoring the last real fix, and shows until the phone sends coordinates. A seed is never saved, so the fix on flash stays as it was for the next launch without one. More...
struct  StockConfig
 The rules a face hands the store, built from its own settings so the store names no SETTING_*. More...
struct  StockSeed
 Optional prefill: shown until the first real reading lands, or pinned when live = false. More...
struct  StoreFetch
 One store's polling state, its catch-up timer, and how it asks the phone. More...
struct  StorePoll
 One store's polling: its interval, whether it polls at all, and when it is next due. More...
struct  SystemConfig
 The rules a face hands the store. More...
struct  SystemSeed
 Optional prefill, or pinned state when live = false. More...
struct  TimeConfig
 The rules a face hands the store, built from its own settings so the store names no SETTING_*. More...
struct  WeatherConfig
 The rules a face hands the store, built from its own settings so the store names no SETTING_*. More...
struct  WeatherSeed
 Optional prefill: shown until the first real reading lands, or pinned when live = false. More...
struct  [struct].s_state

Macros

#define STORE_CADENCE_MAX   8
 Room for one entry per store that wants the cadence.
#define STORE_READING_SIZE(state, stamp)
 How many leading bytes of a store's blob are the reading, which is everything before its sync time.
#define WEATHER_SEED_EMPTY

Typedefs

typedef void(*) BtVibePolicy(bool connected)
 Called on a real bluetooth transition (a change, not the first reading), so the face can buzz however its own settings say. NULL for a silent link change.

Functions

void calendar_store_init (CalendarConfig cfg, const CalendarSeed *seed)
 Start the store with its rules. Pass seed = NULL for normal use.
void calendar_store_reconfigure (CalendarConfig cfg)
 Re-apply the rules (e.g. the poll interval changed). Moves the next poll to the new interval, and switching the store off here stops it asking the phone.
void calendar_store_subscribe (void(*cb)(void))
 Hand it the function to call when the agenda changes (the screen redraw).
const CalendarStrip * calendar_store_strip (void)
 The whole agenda strip. count is 0 until a reading lands.
const CalendarEvent * calendar_store_event (uint8_t index)
 One event by index, or NULL when the index is past what is filled.
int calendar_store_age_s (void)
 How many seconds since the last reading turned up, or -1 if we have none.
void health_store_init (HealthConfig cfg, const HealthSeed *seed)
 Start the store with its rules. Pass seed = NULL for normal use.
void health_store_subscribe (void(*cb)(void))
 Hand it the function to call when the numbers change (the screen redraw).
uint8_t * health_store_hr_history (void)
 The last hour of heart rate readings, one per minute (a 60 slot buffer). The store fills it on each update. The little charts read it back out.
const uint16_t * health_store_step_hourly (void)
 Today's steps split into per-hour buckets, one slot per hour from midnight (24 slots). The bar chart reads it back out.
int health_store_step_hours (void)
 How many of the hourly step buckets hold a real value (0 to 24). Steps count 0 as a real reading (a quiet hour), so a chart needs the count rather than a no-data marker.
int health_store_hr (void)
 The heart rate in beats per minute, or -1 if we have not got one yet.
int health_store_steps (void)
 The steps taken so far today, or -1 if we have not got one yet.
int health_store_calories (void)
 The active calories so far today, or -1 if we have not got one yet.
int health_store_sleep_min (void)
 The minutes of sleep, or -1 if we have not got one yet.
int health_store_active_min (void)
 The active minutes so far today, or -1 if we have not got one yet.
int health_store_distance_m (void)
 Today's walked distance in meters, or 0 if we cannot read it.
void location_store_init (LocationConfig cfg, const LocationSeed *seed)
 Start the store with its rules. Pass seed = NULL for normal use.
void location_store_subscribe (void(*cb)(void))
 Hand it the function to call when the coordinates change (the screen redraw).
const char * location_store_lat (void)
 The latitude string, or empty if we have not got one yet.
const char * location_store_lon (void)
 The longitude string, or empty if we have not got one yet.
void stock_store_init (StockConfig cfg, const StockSeed *seed)
 Start the store with its rules. Pass seed = NULL for normal use.
void stock_store_reconfigure (StockConfig cfg)
 Re-apply the rules (e.g. the poll interval changed). Moves the next poll to the new interval, and switching the store off here stops it asking the phone.
void stock_store_subscribe (void(*cb)(void))
 Hand it the function to call when a quote changes (the screen redraw).
const StockStrip * stock_store_strip (void)
 The whole watchlist strip. count is 0 until a reading lands.
const StockSlot * stock_store_slot (uint8_t index)
 One slot by index, or NULL when the index is past what is filled.
int stock_store_age_s (void)
 How many seconds since the last reading turned up, or -1 if we have none.
void store_cadence_register (void(*cb)(void))
 Ask for cb to run each time the face's cadence comes round. A store calls this from its own init, so no face has to wire it up by hand.
void store_cadence_fire (void)
 Run everything registered, in the order it was registered. The time store calls this from its ticker, before it tells the face the time moved.
void store_fetch_fire (void *data)
 The one-shot fetch's timer callback. Clears the timer and asks the phone.
void store_fetch_stop (StoreFetch *fetch)
 Cancel the one-shot fetch, if one is armed.
void store_fetch_arm (StoreFetch *fetch)
 Arm the one-shot fetch after first_ms, unless one is already waiting.
void store_fetch_turn (StoreFetch *fetch, time_t now)
 The store's turn on the face's cadence. Asks the phone when the deadline has come round.
void store_fetch_start (StoreFetch *fetch, int poll_min, bool live, time_t now)
 What a store's init does with its polling. Takes the interval, then arms one fetch shortly after launch when polling is on, so the store is not blank while the first deadline is coming.
void store_fetch_reconfigure (StoreFetch *fetch, int poll_min, bool live, time_t now, bool empty)
 What a store's reconfigure does with its polling.
static bool store_restore (uint32_t key, void *state, size_t size, uint8_t tag)
 Restore a saved blob into state, but only when it is this store's own current layout.
static bool store_save (uint32_t key, void *state, size_t size, uint8_t tag)
 Save a store's blob with its tag stamped in, so the next restore can recognize it.
bool store_save_changed (uint32_t key, void *state, size_t size, size_t reading_size, uint8_t tag, uint32_t *saved_sum)
 Save a store's blob only when its reading is different from what is already on flash.
bool store_restore_reading (uint32_t key, void *state, size_t size, size_t reading_size, uint8_t tag, uint32_t *saved_sum)
 Restore a saved blob as store_restore does, and record the sum of the reading it holds.
static time_t store_poll_next (int poll_min, time_t now)
 The next wall-clock second a poll of this interval falls due.
static bool store_poll_due (int poll_min, time_t *next, time_t now)
 Whether next has come round, moving it on to the following deadline when it has.
static bool store_poll_reconnect_due (int age_s, int poll_min)
 Whether a reading is worth asking for again now that the phone is back.
bool store_poll_set (StorePoll *poll, int poll_min, bool live, time_t now)
 Take a store's interval and whether it is live, as its init and its reconfigure both do.
bool store_poll_turn (StorePoll *poll, time_t now)
 A store's turn on the face's cadence: whether a poll should go out now.
uint32_t store_sum (const void *bytes, size_t size)
 Sums a run of bytes, so two readings can be compared without keeping both.
void system_store_init (SystemConfig cfg, const SystemSeed *seed)
 Start the store with its rules. Pass seed = NULL for normal use.
void system_store_deinit (void)
 Stop tracking the battery + connection services.
void system_store_subscribe (void(*cb)(void))
 Hand it the function to call when something changes (the screen redraw).
void system_store_on_reconnect (void(*cb)(void))
 Hand it the function to call when the phone app link comes back after a drop.
int system_store_battery (void)
 How full the battery is from 0 to 100.
bool system_store_charging (void)
 True while the watch is plugged in.
bool system_store_bluetooth (void)
 True when the phone link is up.
bool system_store_next_alarm (time_t *out)
 When the wearer's next enabled alarm fires.
void time_store_init (TimeConfig cfg, const struct tm *seed)
 Start the store with its rules. Pass seed = NULL to start from the current time.
void time_store_reconfigure (TimeConfig cfg)
 Re-apply the rules (e.g. the time format changed). Swaps the ticker to match.
void time_store_subscribe (void(*cb)(void))
 Hand it the function to call when the time changes (the screen redraw).
const struct tm * time_store_tm (void)
 The time we hold right now.
void weather_store_init (WeatherConfig cfg, const WeatherSeed *seed)
 Start the store with its rules. Pass seed = NULL for normal use.
void weather_store_reconfigure (WeatherConfig cfg)
 Re-apply the rules (e.g. the poll interval changed). Moves the next poll to the new interval, and switching the store off here stops it asking the phone.
void weather_store_subscribe (void(*cb)(void))
 Hand it the function to call when the weather changes (the screen redraw).
int weather_store_temp (void)
 The temperature reading in the user's unit, or WEATHER_NO_TEMP if we have not got one yet.
const char * weather_store_cond (void)
 The short word for the sky, or empty if we have not got one yet.
const char * weather_store_cond_label (void)
 The sky in words, such as "Partly Cloudy", for a face that declares WEATHER_CONDITION_LABEL.
int weather_store_humidity (void)
 The humidity in percent, or -1 if we have not got one yet.
int weather_store_wind_kmh (void)
 The wind speed in km/h, or -1 if we have not got one yet.
const char * weather_store_wind_dir (void)
 The wind direction like "NW", or empty if we have not got one yet.
int weather_store_sunrise (void)
 Sunrise as minutes past midnight, or -1 if we have not got one yet.
int weather_store_sunset (void)
 Sunset as minutes past midnight, or -1 if we have not got one yet.
int weather_store_feels_like (void)
 How warm it feels, or WEATHER_NO_TEMP if we have not got one yet.
int weather_store_pressure (void)
 The sea level pressure in hPa, or -1 if we have not got one yet.
int weather_store_dew_point (void)
 The dew point temperature, or WEATHER_NO_TEMP if we have not got one yet.
int weather_store_uv (void)
 Today's UV index, or -1 if we have not got one yet or the day it came is over.
int weather_store_temp_max (void)
 Today's high, or WEATHER_NO_TEMP if we have not got one yet or the day it came is over.
int weather_store_temp_min (void)
 Today's low, or WEATHER_NO_TEMP if we have not got one yet or the day it came is over.
int weather_store_precip_chance (void)
 Today's chance of rain in percent, or -1 if we have not got one yet or the day it came is over.
const WeatherHourly * weather_store_forecast_hourly (void)
 The hourly forecast strip, starting at the hour now.
const WeatherDaily * weather_store_forecast_daily (void)
 The daily forecast strip, starting today.
int weather_store_age_s (void)
 How many seconds since the last reading turned up, or -1 if we have none.

Store tags

Every store stamps the first byte of its blob with a tag. The high nibble names the store and the low nibble is that store's layout revision.

The size on its own cannot tell two blobs apart. Reordering two fields keeps the size, and so can two different structs, so the tag is what makes the guard mean anything. Bump a store's low nibble whenever its persisted struct changes shape, and an older blob is dropped rather than read as the wrong thing.

#define STORE_TAG_WEATHER   0x13
 The weather store's blob.
#define STORE_TAG_STOCK   0x21
 The stock store's blob.
#define STORE_TAG_CALENDAR   0x31
 The calendar store's snapshot.
#define STORE_TAG_HEALTH   0x42
 The health store's saved heart rate window.
#define STORE_TAG_LOCATION   0x51
 The location store's last fix.

Detailed Description

Weather, health, calendar, stocks, and the other readings a face shows.

Each store keeps its reading fresh and nudges the screen when it changes.

Macro Definition Documentation

◆ STORE_READING_SIZE

#define STORE_READING_SIZE ( state,
stamp )
Value:
((size_t)((const uint8_t *)&(state).stamp - (const uint8_t *)&(state)))

How many leading bytes of a store's blob are the reading, which is everything before its sync time.

Parameters
stateThe store's blob.
stampThe name of its sync time field, which has to come after every reading.

◆ WEATHER_SEED_EMPTY

#define WEATHER_SEED_EMPTY
Value:
.temp = WEATHER_NO_TEMP, .cond = "", \
.humidity = -1, .wind_kmh = -1, .wind_dir = "", \
.cond_label = NULL, .sunrise = -1, .sunset = -1, .uv = -1, \
.temp_max = WEATHER_NO_TEMP, .temp_min = WEATHER_NO_TEMP, \
.precip_chance = -1, \
.feels_like = WEATHER_NO_TEMP, .pressure = -1, \
.dew_point = WEATHER_NO_TEMP, \
.forecast_hourly = NULL, .forecast_daily = NULL })
Optional prefill: shown until the first real reading lands, or pinned when live = false.
Definition weather_store.h:36
#define WEATHER_NO_TEMP
A column with no reading, so the watch draws a placeholder.
Definition wire_caps.g.h:30

A WeatherSeed with every optional reading already set to its no-data value. Spread it and override only what you have, so a partial seed still reads as "--" instead of a bogus 0. Copy it from a named static const, which the linker drops with the dev code in a release build. Written straight into a local, it leaves an unnamed copy in .data that every build keeps.

static const WeatherSeed s_empty = WEATHER_SEED_EMPTY;
WeatherSeed seed = s_empty;
seed.temp = 23;
seed.cond = "CLEAR";
#define WEATHER_SEED_EMPTY
Definition weather_store.h:66
int16_t temp
Reading in the user's unit, WEATHER_NO_TEMP for none.
Definition weather_store.h:37
const char * cond
Short word for the sky like "SUNNY".
Definition weather_store.h:38

Typedef Documentation

◆ BtVibePolicy

typedef void(*) BtVibePolicy(bool connected)

Called on a real bluetooth transition (a change, not the first reading), so the face can buzz however its own settings say. NULL for a silent link change.

Parameters
connectedTrue when the link just came up, false when it just dropped.

Function Documentation

◆ calendar_store_event()

const CalendarEvent * calendar_store_event ( uint8_t index)

One event by index, or NULL when the index is past what is filled.

Parameters
indexWhich event to read (0 based).
Returns
The event, or NULL.

◆ calendar_store_init()

void calendar_store_init ( CalendarConfig cfg,
const CalendarSeed * seed )

Start the store with its rules. Pass seed = NULL for normal use.

Parameters
cfgThe rules (live / poll interval).
seedOptional prefill, or NULL.

◆ calendar_store_reconfigure()

void calendar_store_reconfigure ( CalendarConfig cfg)

Re-apply the rules (e.g. the poll interval changed). Moves the next poll to the new interval, and switching the store off here stops it asking the phone.

Parameters
cfgThe new rules.

◆ health_store_init()

void health_store_init ( HealthConfig cfg,
const HealthSeed * seed )

Start the store with its rules. Pass seed = NULL for normal use.

Parameters
cfgThe rules (live).
seedOptional prefill, or NULL.

◆ location_store_init()

void location_store_init ( LocationConfig cfg,
const LocationSeed * seed )

Start the store with its rules. Pass seed = NULL for normal use.

Parameters
cfgThe rules (live / persist_key).
seedOptional prefill, or NULL.

◆ stock_store_init()

void stock_store_init ( StockConfig cfg,
const StockSeed * seed )

Start the store with its rules. Pass seed = NULL for normal use.

Parameters
cfgThe rules (live / poll interval).
seedOptional prefill, or NULL.

◆ stock_store_reconfigure()

void stock_store_reconfigure ( StockConfig cfg)

Re-apply the rules (e.g. the poll interval changed). Moves the next poll to the new interval, and switching the store off here stops it asking the phone.

Parameters
cfgThe new rules.

◆ stock_store_slot()

const StockSlot * stock_store_slot ( uint8_t index)

One slot by index, or NULL when the index is past what is filled.

Parameters
indexWhich slot to read (0 based).
Returns
The slot, or NULL.

◆ store_cadence_register()

void store_cadence_register ( void(* cb )(void))

Ask for cb to run each time the face's cadence comes round. A store calls this from its own init, so no face has to wire it up by hand.

The cadence is whichever ticker the face runs: the minute tick, or the .beats timer in its place. A face with neither never fires this, so put periodic work here, not work something depends on. Registering the same function twice does nothing.

Parameters
cbThe work to run. NULL is ignored.

◆ store_fetch_arm()

void store_fetch_arm ( StoreFetch * fetch)

Arm the one-shot fetch after first_ms, unless one is already waiting.

Parameters
fetchThe store's fetch state.

◆ store_fetch_fire()

void store_fetch_fire ( void * data)

The one-shot fetch's timer callback. Clears the timer and asks the phone.

Parameters
dataThe StoreFetch the timer was armed for.

◆ store_fetch_reconfigure()

void store_fetch_reconfigure ( StoreFetch * fetch,
int poll_min,
bool live,
time_t now,
bool empty )

What a store's reconfigure does with its polling.

Switching the store off clears the live flag, which stops the cadence turn too, and drops any fetch still waiting. A store that keeps polling keeps its launch fetch, since a settings push that lands in the first second would otherwise cancel it and leave a restored reading stale until the next deadline.

An empty store has nothing to draw, so it catches up right away. One that already holds data waits for its deadline, so a save that only touched colours does not fetch on the spot and spend a metered provider's quota. That deadline is a wall-clock boundary, so a save can bring it nearer but never past the interval's rate.

Parameters
fetchThe store's fetch state.
poll_minMinutes between polls. 0 or less means no polling.
liveTrue on a live face.
nowThe current wall-clock time.
emptyTrue when the store holds nothing to show yet.

◆ store_fetch_start()

void store_fetch_start ( StoreFetch * fetch,
int poll_min,
bool live,
time_t now )

What a store's init does with its polling. Takes the interval, then arms one fetch shortly after launch when polling is on, so the store is not blank while the first deadline is coming.

Parameters
fetchThe store's fetch state.
poll_minMinutes between polls. 0 or less means no polling.
liveTrue on a live face.
nowThe current wall-clock time.

◆ store_fetch_stop()

void store_fetch_stop ( StoreFetch * fetch)

Cancel the one-shot fetch, if one is armed.

Parameters
fetchThe store's fetch state.

◆ store_fetch_turn()

void store_fetch_turn ( StoreFetch * fetch,
time_t now )

The store's turn on the face's cadence. Asks the phone when the deadline has come round.

Parameters
fetchThe store's fetch state.
nowThe current wall-clock time.

◆ store_poll_due()

bool store_poll_due ( int poll_min,
time_t * next,
time_t now )
inlinestatic

Whether next has come round, moving it on to the following deadline when it has.

A clock that jumps forward just fires once and carries on. One that jumps back would strand the deadline more than an interval ahead, so that case is pulled back in.

Parameters
poll_minMinutes between polls. 0 or less means polling is off and this is never due.
[in,out]nextThe store's deadline, read and updated in place.
nowThe current wall-clock time.
Returns
Whether a poll should go out now.

◆ store_poll_next()

time_t store_poll_next ( int poll_min,
time_t now )
inlinestatic

The next wall-clock second a poll of this interval falls due.

Counted from the epoch rather than from launch, so two watches started minutes apart poll at the same moments and a relaunch does not shift the phase.

Parameters
poll_minMinutes between polls. Must be above 0.
nowThe current wall-clock time.
Returns
The second the next poll is due.

◆ store_poll_reconnect_due()

bool store_poll_reconnect_due ( int age_s,
int poll_min )
inlinestatic

Whether a reading is worth asking for again now that the phone is back.

The phone's side may have been closed the whole time it was away, so a face catches up a reading that went stale meanwhile. Only a reading that never arrived, or one at least its own interval old, is asked for, so bluetooth dropping in and out cannot fetch faster than the normal polling. Polling turned off is left alone, the same as its store.

Parameters
age_sSeconds since the reading arrived, or below 0 when it never has.
poll_minMinutes between polls. 0 or less means polling is off.
Returns
Whether to ask for the reading again.

◆ store_poll_set()

bool store_poll_set ( StorePoll * poll,
int poll_min,
bool live,
time_t now )

Take a store's interval and whether it is live, as its init and its reconfigure both do.

Both are always recorded. The deadline only moves when polling is on, and then to the next interval boundary, so a save can bring a poll nearer but never make one come faster than the interval allows.

Parameters
[in,out]pollThe store's polling state.
poll_minMinutes between polls. 0 or less turns polling off.
liveWhether the store is live.
nowThe current wall-clock time.
Returns
Whether polling is on, which is when a store may arm its first or catch-up fetch.

◆ store_poll_turn()

bool store_poll_turn ( StorePoll * poll,
time_t now )

A store's turn on the face's cadence: whether a poll should go out now.

Parameters
[in,out]pollThe store's polling state. The deadline moves on when a poll is due.
nowThe current wall-clock time.
Returns
Whether to ask the phone now.

◆ store_restore()

bool store_restore ( uint32_t key,
void * state,
size_t size,
uint8_t tag )
inlinestatic

Restore a saved blob into state, but only when it is this store's own current layout.

Checks the size and then the tag byte. Nothing is written into state unless both match, so the defaults the caller applied before calling survive a rejected blob.

Parameters
keyThe persist slot the face handed the store.
[out]stateThe struct to fill. Its first field must be the uint8_t tag.
sizesizeof that struct.
tagThe store's STORE_TAG_* value.
Returns
Whether a saved blob was restored.

◆ store_restore_reading()

bool store_restore_reading ( uint32_t key,
void * state,
size_t size,
size_t reading_size,
uint8_t tag,
uint32_t * saved_sum )

Restore a saved blob as store_restore does, and record the sum of the reading it holds.

The sum is what store_save_changed compares against, so a first reply bringing the same reading after a relaunch is not written again.

Parameters
keyThe persist slot the face handed the store.
[out]stateThe struct to fill. Its first field must be the uint8_t tag.
sizesizeof that struct.
reading_sizeHow many leading bytes are the reading, from STORE_READING_SIZE.
tagThe store's STORE_TAG_* value.
[out]saved_sumThe sum of the restored reading, or 0 when nothing was restored.
Returns
Whether a saved blob was restored.

◆ store_save()

bool store_save ( uint32_t key,
void * state,
size_t size,
uint8_t tag )
inlinestatic

Save a store's blob with its tag stamped in, so the next restore can recognize it.

Parameters
keyThe persist slot the face handed the store.
[in,out]stateThe struct to write, with its tag stamped in on the way. Its first field must be the uint8_t tag.
sizesizeof that struct.
tagThe store's STORE_TAG_* value.
Returns
Whether the whole blob reached flash. False means the cache did not land, so a caller that tracks a dirty flag can hold it and try again.

◆ store_save_changed()

bool store_save_changed ( uint32_t key,
void * state,
size_t size,
size_t reading_size,
uint8_t tag,
uint32_t * saved_sum )

Save a store's blob only when its reading is different from what is already on flash.

Only the first reading_size bytes are compared, so a reply that brings the same reading with a new sync time writes nothing. The flash copy then keeps the sync time of the last real change, and a relaunch reads the reading as older than it is. The catch-up poll after a reconnect fires a little sooner for it, which costs one request at most.

Parameters
keyThe persist slot the face handed the store.
[in,out]stateThe struct to write, with its tag stamped in on the way. Its first field must be the uint8_t tag.
sizesizeof that struct.
reading_sizeHow many leading bytes are the reading, from STORE_READING_SIZE. Pass the whole size for a blob with no sync time.
tagThe store's STORE_TAG_* value.
[in,out]saved_sumThe sum of the reading last written, which the store keeps. It moves on only when a write lands.
Returns
Whether flash holds this reading now, because it already did or because the write landed. False means the write failed, so a caller that tracks a dirty flag can try again.

◆ store_sum()

uint32_t store_sum ( const void * bytes,
size_t size )

Sums a run of bytes, so two readings can be compared without keeping both.

FNV-1a, which mixes each byte in turn. A plain byte total would miss two values swapping places, and a reading that only reordered its forecast would never be saved.

Parameters
bytesThe bytes to sum.
sizeHow many there are.
Returns
The sum.

◆ system_store_init()

void system_store_init ( SystemConfig cfg,
const SystemSeed * seed )

Start the store with its rules. Pass seed = NULL for normal use.

Parameters
cfgThe rules (live / vibe policy).
seedOptional prefill, or NULL.

◆ system_store_next_alarm()

bool system_store_next_alarm ( time_t * out)

When the wearer's next enabled alarm fires.

Read through to the alarm service on every call, since there is nothing to subscribe to. A platform without the alarm API always reads as no alarm.

Parameters
[out]outSet to the alarm's UTC time, or 0 when there is none. Never NULL.
Returns
True when an enabled alarm is scheduled.

◆ time_store_init()

void time_store_init ( TimeConfig cfg,
const struct tm * seed )

Start the store with its rules. Pass seed = NULL to start from the current time.

Parameters
cfgThe rules (live / cadence).
seedOptional time to pin (dev/screenshots), or NULL for the current time.

◆ time_store_reconfigure()

void time_store_reconfigure ( TimeConfig cfg)

Re-apply the rules (e.g. the time format changed). Swaps the ticker to match.

Parameters
cfgThe new rules.

◆ weather_store_cond_label()

const char * weather_store_cond_label ( void )

The sky in words, such as "Partly Cloudy", for a face that declares WEATHER_CONDITION_LABEL.

Returns
The label, or empty when the phone sent none.

◆ weather_store_forecast_daily()

const WeatherDaily * weather_store_forecast_daily ( void )

The daily forecast strip, starting today.

Days before today come off the front as it is read, and base_weekday moves with them.

Returns
The strip. count is 0 until a reading lands, or once every day is over.

◆ weather_store_forecast_hourly()

const WeatherHourly * weather_store_forecast_hourly ( void )

The hourly forecast strip, starting at the hour now.

A strip can outlive the fetch that brought it, when only the forecast half of a later fetch fails. Columns whose hour is over come off the front as it is read, and base_hour moves with them, so a column is never labelled with an hour already gone.

Returns
The strip. count is 0 until a reading lands, or once every column is over.

◆ weather_store_init()

void weather_store_init ( WeatherConfig cfg,
const WeatherSeed * seed )

Start the store with its rules. Pass seed = NULL for normal use.

Parameters
cfgThe rules (live / poll interval).
seedOptional prefill, or NULL.

◆ weather_store_reconfigure()

void weather_store_reconfigure ( WeatherConfig cfg)

Re-apply the rules (e.g. the poll interval changed). Moves the next poll to the new interval, and switching the store off here stops it asking the phone.

Parameters
cfgThe new rules.