Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fitness App: Make stored steps sample smaller as it passed max settin… #368

Merged
merged 2 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 39 additions & 12 deletions app/src/applications/fitness/fitness_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,25 @@ LOG_MODULE_REGISTER(fitness_app, LOG_LEVEL_INF);
#define STEP_RESET_COUNTER_INTERVAL_S 50
#define DAYS_IN_WEEK 7

#define SETTING_BATTERY_HIST "fitness/step/hist"
#define SAMPLE_INTERVAL_MIN 60
#define SAMPLE_INTERVAL_MS (SAMPLE_INTERVAL_MIN * 60 * 1000)
#define MAX_SAMPLES (7 * 24) // One week of hourly samples
#define SETTING_FITNESS_HIST_KEY "fitness/step/hist"
#define SAMPLE_INTERVAL_MIN 60
#define SAMPLE_INTERVAL_MS (SAMPLE_INTERVAL_MIN * 60 * 1000)
#define MAX_SAMPLES (7 * 24) // One week of hourly samples

typedef struct minimal_zsw_timeval {
// Same structure as zsw_timeval_t, but with smaller types and without tm_isdst and nanoseconds
uint8_t tm_sec; /**< Seconds [0, 59] */
uint8_t tm_min; /**< Minutes [0, 59] */
uint8_t tm_hour; /**< Hours [0, 23] */
uint8_t tm_mday; /**< Day of the month [1, 31] */
uint8_t tm_mon; /**< Month [0, 11] */
uint16_t tm_year; /**< Year */
uint8_t tm_wday; /**< Day of the week [0, 6] (Sunday = 0) (Unknown = -1) */
uint16_t tm_yday; /**< Day of the year [0, 365] (Unknown = -1) */
} minimal_zsw_timeval_t;

typedef struct {
zsw_timeval_t time; // TODO optimize size as NVS settings backend can do < 4096 bytes per store
minimal_zsw_timeval_t time;
uint32_t steps;
} zsw_step_sample_t;

Expand Down Expand Up @@ -80,9 +92,22 @@ static void step_work_callback(struct k_work *work)
}
}

static void timeval_to_minimal_timeval(zsw_timeval_t *time, minimal_zsw_timeval_t *minimal_time)
{
minimal_time->tm_sec = time->tm.tm_sec;
minimal_time->tm_min = time->tm.tm_min;
minimal_time->tm_hour = time->tm.tm_hour;
minimal_time->tm_mday = time->tm.tm_mday;
minimal_time->tm_mon = time->tm.tm_mon;
minimal_time->tm_year = time->tm.tm_year;
minimal_time->tm_wday = time->tm.tm_wday;
minimal_time->tm_yday = time->tm.tm_yday;
}

static void step_sample_work(struct k_work *work)
{
zsw_step_sample_t sample;
zsw_timeval_t time_now;
int next_sample_seconds;

if (zsw_imu_fetch_num_steps(&sample.steps) != 0) {
Expand All @@ -93,14 +118,16 @@ static void step_sample_work(struct k_work *work)
return;
#endif
}
zsw_clock_get_time(&sample.time);
zsw_clock_get_time(&time_now);
timeval_to_minimal_timeval(&time_now, &sample.time);

zsw_history_add(&fitness_history_context, &sample);
if (zsw_history_save(&fitness_history_context)) {
LOG_ERR("Error during saving of step samples!");
}
LOG_DBG("Step sample hist add: %d", sample.steps);
LOG_DBG("Time: %d:%d:%d", sample.time.tm.tm_hour, sample.time.tm.tm_min, sample.time.tm.tm_sec);
next_sample_seconds = 60 * (SAMPLE_INTERVAL_MIN - sample.time.tm.tm_min) - sample.time.tm.tm_sec;
LOG_DBG("Time: %d:%d:%d", sample.time.tm_hour, sample.time.tm_min, sample.time.tm_sec);
next_sample_seconds = 60 * (SAMPLE_INTERVAL_MIN - sample.time.tm_min) - sample.time.tm_sec;
LOG_DBG("Next sample in %d:%d", next_sample_seconds / 60, next_sample_seconds % 60);
k_work_reschedule(&sample_step_work, K_SECONDS(next_sample_seconds));
}
Expand All @@ -113,8 +140,8 @@ static void get_steps_per_day(uint16_t weekdays[DAYS_IN_WEEK])
for (int i = 0; i < num_samples; i++) {
zsw_step_sample_t sample;
zsw_history_get(&fitness_history_context, &sample, i);
day = sample.time.tm.tm_wday;
LOG_DBG("Day: %d, HH: %d, Steps: %d", day, sample.time.tm.tm_hour, sample.steps);
day = sample.time.tm_wday;
LOG_DBG("Day: %d, HH: %d, Steps: %d", day, sample.time.tm_hour, sample.steps);
weekdays[day] = MAX(sample.steps, weekdays[day]);
}
}
Expand Down Expand Up @@ -192,7 +219,7 @@ static int fitness_app_add(void)
k_work_reschedule(&step_work, K_SECONDS(STEP_RESET_COUNTER_INTERVAL_S));
#endif

zsw_history_init(&fitness_history_context, MAX_SAMPLES, sizeof(zsw_step_sample_t), samples, SETTING_BATTERY_HIST);
zsw_history_init(&fitness_history_context, MAX_SAMPLES, sizeof(zsw_step_sample_t), samples, SETTING_FITNESS_HIST_KEY);

if (zsw_history_load(&fitness_history_context)) {
LOG_ERR("Error during settings_load_subtree!");
Expand All @@ -204,7 +231,7 @@ static int fitness_app_add(void)
zsw_clock_get_time(&time);

// If watch was reset the step counter restarts at 0, so we need to update the offset.
if (num_hist_samples > 0 && time.tm.tm_mday == samples[num_hist_samples - 1].time.tm.tm_mday) {
if (num_hist_samples > 0 && time.tm.tm_mday == samples[num_hist_samples - 1].time.tm_mday) {
zsw_imu_set_step_offset(samples[num_hist_samples - 1].steps);
}

Expand Down
25 changes: 20 additions & 5 deletions app/src/history/zsw_history.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/settings/settings.h>

#ifdef CONFIG_SETTINGS_NVS
#include <zephyr/fs/nvs.h>
#endif
#include "zsw_history.h"

#define ZSW_HISTORY_HEADER_EXTENSION "head"
Expand Down Expand Up @@ -73,7 +75,7 @@ static int zsw_history_load_data_cb(const char *p_key, size_t len, settings_read
int zsw_history_init(zsw_history_t *p_history, uint32_t max_samples, uint8_t sample_size, void *p_samples,
const char *p_key)
{
int32_t error;
int32_t rc;

__ASSERT((p_history != NULL) && (p_samples != NULL) && (p_key != NULL), "Invalid parameters for zsw_history_init");

Expand All @@ -86,12 +88,25 @@ int zsw_history_init(zsw_history_t *p_history, uint32_t max_samples, uint8_t sam
memset(p_samples, 0, max_samples * sample_size);
strcpy(p_history->key, p_key);

error = settings_subsys_init();
if (error) {
LOG_ERR("Error during settings initialization! Error: %i", error);
rc = settings_subsys_init();
if (rc) {
LOG_ERR("Error during settings initialization! Error: %i", rc);
return -EFAULT;
}

#ifdef CONFIG_SETTINGS_NVS
struct nvs_fs *nvs_storage;

rc = settings_storage_get(&nvs_storage);
__ASSERT(rc == 0, "Error during settings storage get! Error: %d", rc);

// As long as history is storing all samples as one key, we have a limit of NVS sector size for total size of samples
// TODO: Should store history not as one big chunk as it's not very efficient for flash wear.
#define NVS_ESTIMATED_OVERHEAD 100
__ASSERT(max_samples * sample_size < (nvs_storage->sector_size - NVS_ESTIMATED_OVERHEAD),
"NVS sector size too small! history of %d has to fit one NVS page of %d", max_samples * sample_size,
(nvs_storage->sector_size - NVS_ESTIMATED_OVERHEAD));
#endif
return 0;
}

Expand Down