mirror of
https://github.com/google/pebble.git
synced 2025-03-28 05:47:46 +00:00
235 lines
9.2 KiB
C
235 lines
9.2 KiB
C
/*
|
|
* Copyright 2024 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "clar.h"
|
|
|
|
#include "services/normal/activity/activity.h"
|
|
#include "services/normal/activity/activity_private.h"
|
|
#include "services/normal/activity/activity_calculators.h"
|
|
|
|
#include "util/units.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
// Fakes
|
|
static uint8_t s_age_years;
|
|
uint8_t activity_prefs_get_age_years(void) {
|
|
return s_age_years;
|
|
}
|
|
|
|
static ActivityGender s_gender;
|
|
ActivityGender activity_prefs_get_gender(void) {
|
|
return s_gender;
|
|
}
|
|
|
|
static uint16_t s_weight_dag;
|
|
uint16_t activity_prefs_get_weight_dag(void) {
|
|
return s_weight_dag;
|
|
}
|
|
|
|
static uint16_t s_height_mm;
|
|
uint16_t activity_prefs_get_height_mm(void) {
|
|
return s_height_mm;
|
|
}
|
|
|
|
typedef enum {
|
|
Human_TallMale,
|
|
Human_ShortMale,
|
|
Human_TallFemale,
|
|
Human_ShortFemale,
|
|
Human_Count,
|
|
} Human;
|
|
|
|
typedef struct HumanPrefs {
|
|
uint8_t age_years;
|
|
ActivityGender gender;
|
|
uint16_t weight_dag;
|
|
uint16_t height_mm;
|
|
} HumanPrefs;
|
|
|
|
#define ACTIVITY_DEFAULT_HEIGHT_MM 1620 // 5'3.8"
|
|
// dag - decagram (10 g)
|
|
#define ACTIVITY_DEFAULT_WEIGHT_DAG 7539 // 166.2 lbs
|
|
#define ACTIVITY_DEFAULT_GENDER ActivityGenderFemale
|
|
#define ACTIVITY_DEFAULT_AGE_YEARS 30
|
|
|
|
static void prv_set_user(Human type) {
|
|
const HumanPrefs types[Human_Count] = {
|
|
[Human_TallMale] = {30, ActivityGenderMale, 7539, 1900},
|
|
[Human_ShortMale] = {30, ActivityGenderMale, 4536, 1620},
|
|
[Human_TallFemale] = {30, ActivityGenderFemale, 7539, 1900},
|
|
[Human_ShortFemale] = {30, ActivityGenderFemale, 4536, 1620},
|
|
};
|
|
|
|
s_age_years = types[type].age_years;
|
|
s_gender = types[type].gender;
|
|
s_weight_dag = types[type].weight_dag;
|
|
s_height_mm = types[type].height_mm;
|
|
}
|
|
|
|
#define MM_PER_METER 1000
|
|
#define M_PER_KM 1000
|
|
|
|
// =============================================================================================
|
|
// Start of unit tests
|
|
void test_activity_calculators__initialize(void) {
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
void test_activity_calculators__cleanup(void) {
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
void test_activity_calculators__distance(void) {
|
|
uint32_t steps;
|
|
uint32_t time_ms;
|
|
|
|
prv_set_user(Human_TallMale);
|
|
|
|
const int walking_cadence_spm = 100;
|
|
|
|
// Do an normal walk for 12 mins. An average person should cover ~1km
|
|
const int walk_time = 12;
|
|
steps = walking_cadence_spm * walk_time;
|
|
time_ms = walk_time * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int easy_walk_distance_m = activity_private_compute_distance_mm(steps, time_ms) / MM_PER_METER;
|
|
cl_assert_within(easy_walk_distance_m, 900, 1100);
|
|
|
|
// Walk for 12 mins again, but this time faster. More distance should be covered
|
|
steps = (walking_cadence_spm * 1.2) * walk_time;
|
|
time_ms = walk_time * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int fast_walk_distance_m = activity_private_compute_distance_mm(steps, time_ms) / MM_PER_METER;
|
|
cl_assert_gt(fast_walk_distance_m, easy_walk_distance_m);
|
|
|
|
// Walk for a long time. People can walk at roughly 5km/h, so we should be close to 50km
|
|
const int long_walk_time = 10 * MINUTES_PER_HOUR;
|
|
steps = walking_cadence_spm * long_walk_time;
|
|
time_ms = long_walk_time * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int long_walk_distance_m = activity_private_compute_distance_mm(steps, time_ms) / MM_PER_METER;
|
|
cl_assert_within(long_walk_distance_m, 48000, 52000);
|
|
|
|
|
|
// A typical cadence is roughly 165 steps per minute
|
|
const int running_cadence_spm = 165;
|
|
|
|
// Running for 25 minutes should come out to roughly 5km
|
|
const int run_time = 25;
|
|
steps = running_cadence_spm * run_time;
|
|
time_ms = run_time * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int normal_run_distance_m = activity_private_compute_distance_mm(steps, time_ms) / MM_PER_METER;
|
|
cl_assert_within(normal_run_distance_m, 4500, 5500);
|
|
|
|
// Running for 25 minutes again, but this time faster
|
|
steps = (running_cadence_spm * 1.15) * run_time;
|
|
time_ms = run_time * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int fast_run_distance_m = activity_private_compute_distance_mm(steps, time_ms) / MM_PER_METER;
|
|
cl_assert_within(fast_run_distance_m, 6500, 7000);
|
|
cl_assert_gt(fast_run_distance_m, normal_run_distance_m);
|
|
|
|
// Run for 3.5 hours. This is a reasonable marathon time
|
|
const int long_run_time = 3 * MINUTES_PER_HOUR + 30;
|
|
steps = running_cadence_spm * long_run_time;
|
|
time_ms = long_run_time * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int long_run_distance_m = activity_private_compute_distance_mm(steps, time_ms) / MM_PER_METER;
|
|
cl_assert_within(long_run_distance_m, 40000, 44000);
|
|
|
|
// Now make a shorter guy run for the same time.
|
|
// He should be in the same ballpark but cover less distance
|
|
prv_set_user(Human_ShortMale);
|
|
int short_guy_distance = activity_private_compute_distance_mm(steps, time_ms) / MM_PER_METER;
|
|
cl_assert_within(short_guy_distance, 36000, 44000);
|
|
cl_assert_gt(long_run_distance_m, short_guy_distance);
|
|
|
|
// And finally throw in a specific value so that anyone who touches the function will have to
|
|
// check up on the unit tests
|
|
cl_assert_equal_i(short_guy_distance, 36845);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
void test_activity_calculators__active_calories(void) {
|
|
uint32_t distance_mm;
|
|
uint32_t time_ms;
|
|
|
|
prv_set_user(Human_ShortMale);
|
|
|
|
// Walk 1km in 12 minutes
|
|
distance_mm = 1 * M_PER_KM * MM_PER_METER;
|
|
time_ms = 12 * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int walk_calories = activity_private_compute_active_calories(distance_mm, time_ms) / ACTIVITY_CALORIES_PER_KCAL;
|
|
cl_assert_within(walk_calories, 20, 25); // This seems a little low, but not un-reasonable
|
|
|
|
// Run 1km in 5 minutes. This should burn more calories than walking
|
|
distance_mm = 1 * M_PER_KM * MM_PER_METER;
|
|
time_ms = 5 * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int run_calories = activity_private_compute_active_calories(distance_mm, time_ms) / ACTIVITY_CALORIES_PER_KCAL;
|
|
cl_assert_within(run_calories, 40, 60); // This also seems a little low, but not un-reasonable
|
|
cl_assert_gt(run_calories, walk_calories);
|
|
|
|
// Run 5km in 25 minutes
|
|
distance_mm = 5 * M_PER_KM * MM_PER_METER;
|
|
time_ms = 25 * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int five_k_calories = activity_private_compute_active_calories(distance_mm, time_ms) / ACTIVITY_CALORIES_PER_KCAL;
|
|
cl_assert_within(five_k_calories, 220, 250);
|
|
cl_assert_gt(five_k_calories, run_calories);
|
|
|
|
// PG: I went for the following run last night and my garmin watch said I burned 550 calories
|
|
prv_set_user(Human_TallMale);
|
|
distance_mm = 7 * M_PER_KM * MM_PER_METER;
|
|
time_ms = 30 * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int quick_run_calories = activity_private_compute_active_calories(distance_mm, time_ms) / ACTIVITY_CALORIES_PER_KCAL;
|
|
cl_assert_within(quick_run_calories, 520, 580);
|
|
|
|
// Run a marathon
|
|
distance_mm = 42 * M_PER_KM * MM_PER_METER;
|
|
time_ms = 3 * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MS_PER_SECOND;
|
|
int long_run_calories = activity_private_compute_active_calories(distance_mm, time_ms) / ACTIVITY_CALORIES_PER_KCAL;
|
|
cl_assert_within(long_run_calories, 3000, 3200);
|
|
|
|
// And finally throw in a specific value so that anyone who touches the function will have to
|
|
// check up on the unit tests
|
|
cl_assert_equal_i(long_run_calories, 3172);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
void test_activity_calculators__inactive_calories(void) {
|
|
// People burn roughly 2000 (women) - 2400 (men) a day. This number includes active calories
|
|
// so I would expect the values we get to be less than that. I don't know enough to make
|
|
// better real world analogies though...
|
|
|
|
uint32_t long_time_m = 24 * MINUTES_PER_HOUR;
|
|
uint32_t short_time_m = 5;
|
|
|
|
prv_set_user(Human_ShortMale);
|
|
|
|
cl_assert_equal_i(1321, activity_private_compute_resting_calories(long_time_m) / ACTIVITY_CALORIES_PER_KCAL);
|
|
cl_assert_equal_i(4, activity_private_compute_resting_calories(short_time_m) / ACTIVITY_CALORIES_PER_KCAL);
|
|
|
|
prv_set_user(Human_TallMale);
|
|
|
|
cl_assert_equal_i(1796, activity_private_compute_resting_calories(long_time_m)/ ACTIVITY_CALORIES_PER_KCAL);
|
|
cl_assert_equal_i(6, activity_private_compute_resting_calories(short_time_m) / ACTIVITY_CALORIES_PER_KCAL);
|
|
|
|
prv_set_user(Human_ShortFemale);
|
|
|
|
cl_assert_equal_i(1155, activity_private_compute_resting_calories(long_time_m) / ACTIVITY_CALORIES_PER_KCAL);
|
|
cl_assert_equal_i(4, activity_private_compute_resting_calories(short_time_m) / ACTIVITY_CALORIES_PER_KCAL);
|
|
|
|
prv_set_user(Human_TallFemale);
|
|
|
|
cl_assert_equal_i(1630, activity_private_compute_resting_calories(long_time_m) / ACTIVITY_CALORIES_PER_KCAL);
|
|
cl_assert_equal_i(5, activity_private_compute_resting_calories(short_time_m) / ACTIVITY_CALORIES_PER_KCAL);
|
|
|
|
}
|