mirror of
https://github.com/google/pebble.git
synced 2025-03-21 11:21:21 +00:00
278 lines
8.2 KiB
C
278 lines
8.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 "fake_app_manager.h"
|
|
#include "fake_new_timer.h"
|
|
#include "fake_pbl_malloc.h"
|
|
#include "fake_pebble_tasks.h"
|
|
#include "fake_system_task.h"
|
|
|
|
#include "stubs_analytics.h"
|
|
#include "stubs_analytics_external.h"
|
|
#include "stubs_gettext.h"
|
|
#include "stubs_logging.h"
|
|
#include "stubs_logging.h"
|
|
#include "stubs_mutex.h"
|
|
#include "stubs_passert.h"
|
|
#include "stubs_persist.h"
|
|
#include "stubs_prompt.h"
|
|
#include "stubs_queue.h"
|
|
#include "stubs_resources.h"
|
|
#include "stubs_serial.h"
|
|
#include "stubs_syscall_internal.h"
|
|
#include "stubs_worker_manager.h"
|
|
|
|
#include "drivers/accel.h"
|
|
#include "services/common/event_service.h"
|
|
#include "util/math.h"
|
|
#include "util/size.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
// helpers from accel manager
|
|
extern void test_accel_manager_get_subsample_info(
|
|
AccelManagerState *state, uint16_t *num, uint16_t *den, uint16_t *samps_per_update);
|
|
extern void test_accel_manager_reset(void);
|
|
|
|
// stub
|
|
void event_service_init(PebbleEventType type,
|
|
EventServiceAddSubscriberCallback start_cb,
|
|
EventServiceRemoveSubscriberCallback stop_cb) {}
|
|
void sys_vibe_history_start_collecting(void) {}
|
|
void sys_vibe_history_stop_collecting(void) {}
|
|
int32_t sys_vibe_get_vibe_strength(void) {
|
|
return 0;
|
|
}
|
|
void accel_set_shake_sensitivity_high(bool sensitivity_high) {}
|
|
QueueHandle_t pebble_task_get_to_queue(PebbleTask task) {
|
|
return NULL;
|
|
}
|
|
|
|
// fake accel.h impl
|
|
static int s_sampling_interval_us = 1000000 / ACCEL_SAMPLING_25HZ;
|
|
static int s_num_samples = 0;
|
|
|
|
//! If true, ignore attempts to change the sampling interval
|
|
static bool s_force_sampling_interval;
|
|
|
|
uint32_t accel_set_sampling_interval(uint32_t interval_us) {
|
|
if (!s_force_sampling_interval) {
|
|
s_sampling_interval_us = interval_us;
|
|
}
|
|
return accel_get_sampling_interval();
|
|
}
|
|
|
|
uint32_t accel_get_sampling_interval(void) {
|
|
return s_sampling_interval_us;
|
|
}
|
|
|
|
void accel_set_num_samples(uint32_t num_samples) {
|
|
s_num_samples = num_samples;
|
|
}
|
|
int accel_peek(AccelDriverSample *data) {
|
|
return 0;
|
|
}
|
|
void accel_enable_shake_detection(bool on) {
|
|
}
|
|
bool accel_get_shake_detection_enabled(void) {
|
|
return false;
|
|
}
|
|
void accel_enable_double_tap_detection(bool on) {
|
|
}
|
|
bool accel_get_double_tap_detection_enabled(void) {
|
|
return false;
|
|
}
|
|
|
|
bool accel_run_selftest(void) {
|
|
return true;
|
|
}
|
|
|
|
bool gyro_run_selftest(void) {
|
|
return true;
|
|
}
|
|
|
|
bool new_timer_add_work_callback_from_isr(NewTimerWorkCallback cb, void *data) {
|
|
return false;
|
|
}
|
|
bool new_timer_add_work_callback(NewTimerWorkCallback cb, void *data) {
|
|
return true;
|
|
}
|
|
|
|
// Unit Test Code
|
|
|
|
void test_accel_manager__initialize(void) {
|
|
accel_manager_init();
|
|
|
|
s_sampling_interval_us = 1000000 / ACCEL_SAMPLING_25HZ;
|
|
s_num_samples = 0;
|
|
s_force_sampling_interval = false;
|
|
}
|
|
|
|
|
|
void test_accel_manager__cleanup(void) {
|
|
test_accel_manager_reset();
|
|
}
|
|
|
|
static void prv_noop_sample_handler(void *context) {
|
|
|
|
}
|
|
|
|
static void prv_validate_sample_rates(int *arr, int num_samples) {
|
|
for (int i = 0; i < num_samples; i++) {
|
|
// force a compiler error if user has not added all possible sample rates to array
|
|
switch ((AccelSamplingRate)arr[i]) {
|
|
case ACCEL_SAMPLING_10HZ:
|
|
case ACCEL_SAMPLING_25HZ:
|
|
case ACCEL_SAMPLING_50HZ:
|
|
case ACCEL_SAMPLING_100HZ:
|
|
break;
|
|
default:
|
|
cl_assert(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void prv_run_accel_test(int *sample_arr, int num_items) {
|
|
PebbleTask tasks[] = { PebbleTask_KernelMain, PebbleTask_Worker, PebbleTask_App };
|
|
AccelManagerState* sessions[3];
|
|
|
|
if (num_items > 3) {
|
|
return; // we only support 3 simultaneous subscribers
|
|
}
|
|
|
|
int fastest_rate = 0;
|
|
AccelRawData fake_buf[1];
|
|
for (int i = 0; i < num_items; i++) {
|
|
if (fastest_rate < sample_arr[i]) {
|
|
fastest_rate = sample_arr[i];
|
|
}
|
|
|
|
sessions[i] = sys_accel_manager_data_subscribe(
|
|
sample_arr[i], prv_noop_sample_handler, NULL, tasks[i]);
|
|
|
|
// buffer size of 1
|
|
sys_accel_manager_set_sample_buffer(sessions[i], fake_buf, 1);
|
|
}
|
|
|
|
// make sure all sampling rates are what they should be
|
|
for (int i = 0; i < num_items; i++) {
|
|
stub_pebble_tasks_set_current(tasks[i]);
|
|
|
|
uint16_t num, den, samps_per_update;
|
|
test_accel_manager_get_subsample_info(sessions[i], &num, &den, &samps_per_update);
|
|
|
|
if ((fastest_rate % sample_arr[i]) == 0) {
|
|
// the current sample rate is a multiple of the rate we are running at
|
|
cl_assert_equal_i(num, 1);
|
|
cl_assert_equal_i(den, fastest_rate / sample_arr[i]);
|
|
cl_assert_equal_i(samps_per_update, 1);
|
|
} else {
|
|
// the sample rate is not an even multiple of our fastest rate
|
|
uint32_t gcd_of_rates = gcd(fastest_rate, sample_arr[i]);
|
|
cl_assert_equal_i(num, sample_arr[i] / gcd_of_rates);
|
|
cl_assert_equal_i(den, fastest_rate / gcd_of_rates);
|
|
cl_assert_equal_i(samps_per_update, 1);
|
|
}
|
|
}
|
|
|
|
cl_assert_equal_i(1000000 / s_sampling_interval_us, fastest_rate);
|
|
cl_assert_equal_i(s_num_samples, 1);
|
|
|
|
for (int i = 0; i < num_items; i++) {
|
|
sys_accel_manager_data_unsubscribe(sessions[i]);
|
|
stub_pebble_tasks_set_current(tasks[i]);
|
|
}
|
|
}
|
|
|
|
// enumerate through all possible sampling rate combinations and confirm
|
|
// that the correct frequency is selected
|
|
void test_accel_manager__subscription_sampling_rates(void) {
|
|
int sample_rates[] = { ACCEL_SAMPLING_10HZ, ACCEL_SAMPLING_25HZ,
|
|
ACCEL_SAMPLING_50HZ, ACCEL_SAMPLING_100HZ};
|
|
prv_validate_sample_rates(sample_rates, ARRAY_LENGTH(sample_rates));
|
|
|
|
int poss_rates = ARRAY_LENGTH(sample_rates);
|
|
int max_permutations = 0x1 << poss_rates;
|
|
|
|
for (int mask = 0; mask < max_permutations; mask++) {
|
|
int count = __builtin_popcount(mask);
|
|
if (count == 0) {
|
|
continue; // we don't care about the empty set
|
|
}
|
|
|
|
int test_rates[count];
|
|
int idx = 0;
|
|
for (int j = 0; j < poss_rates; j++) {
|
|
if ((mask & (0x1 << j)) != 0) {
|
|
test_rates[idx] = sample_rates[j];
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
printf("Testing: ");
|
|
for (int i = 0; i < count; i++) {
|
|
printf("%d ", sample_rates[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
prv_run_accel_test(test_rates, count);
|
|
}
|
|
}
|
|
|
|
void test_accel_manager__jitterfree(void) {
|
|
// Force the fake accel to only support the 125hz sample rate.
|
|
s_force_sampling_interval = true;
|
|
s_sampling_interval_us = (1000000000 / 125000);
|
|
|
|
AccelRawData fake_buf[1];
|
|
|
|
AccelManagerState *state = sys_accel_manager_data_subscribe(
|
|
ACCEL_SAMPLING_25HZ, prv_noop_sample_handler, NULL, PebbleTask_KernelMain);
|
|
uint32_t resulting_mhz = accel_manager_set_jitterfree_sampling_rate(state, 12500);
|
|
sys_accel_manager_set_sample_buffer(state , fake_buf, ARRAY_LENGTH(fake_buf));
|
|
|
|
cl_assert_equal_i(resulting_mhz, 12500);
|
|
|
|
uint16_t num, den, samples_per_update;
|
|
test_accel_manager_get_subsample_info(state, &num, &den, &samples_per_update);
|
|
|
|
cl_assert_equal_i(num, 1);
|
|
cl_assert_equal_i(den, 10);
|
|
cl_assert_equal_i(samples_per_update, ARRAY_LENGTH(fake_buf));
|
|
}
|
|
|
|
|
|
void test_accel_manager__batched_samples(void) {
|
|
AccelRawData fake_buf[30];
|
|
|
|
stub_pebble_tasks_set_current(PebbleTask_KernelMain);
|
|
AccelManagerState *main_session = sys_accel_manager_data_subscribe(
|
|
ACCEL_SAMPLING_10HZ, prv_noop_sample_handler, NULL, PebbleTask_KernelMain);
|
|
sys_accel_manager_set_sample_buffer(main_session, fake_buf, 11);
|
|
|
|
stub_pebble_tasks_set_current(PebbleTask_Worker);
|
|
AccelManagerState *worker_session = sys_accel_manager_data_subscribe(
|
|
ACCEL_SAMPLING_25HZ, prv_noop_sample_handler, NULL, PebbleTask_KernelMain);
|
|
sys_accel_manager_set_sample_buffer(worker_session, fake_buf, 22);
|
|
|
|
cl_assert_equal_i(s_num_samples, 22);
|
|
|
|
stub_pebble_tasks_set_current(PebbleTask_KernelMain);
|
|
sys_accel_manager_set_sample_buffer(main_session, fake_buf, 3);
|
|
cl_assert_equal_i(s_num_samples, 7); /* 300ms / (1000ms / 25 samps) */
|
|
}
|