diff --git a/Makefile b/Makefile index ca10bbc..782c775 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,4 @@ -# TODO: update this. -PHONY = default echo/objects echo/sources list tests run bin clean +PHONY = default echo/objects echo/sources list tests bin/tests run bin clean SOURCES_C = $(wildcard src/*.c) TEST_CC = $(wildcard test/*.cc) @@ -11,8 +10,9 @@ TEST_OBJECTS = $(subst test,bin,$(_TEST_OBJECTS_TMP)) EXEC = tests +# Pebble args: -std=c99 -fdata-sections -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-error=unused-function -Wno-error=unused-variable -fPIE -DRELEASE -Os # removed: -Wl,-z,relro -Wl,-z,now -C_ARGS = -DIS_NOT_PEBBLE -pipe -m64 -ansi -fPIC -g -O3 -fno-exceptions -fstack-protector -fvisibility=hidden -W -Wall -Wno-unused-parameter -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wformat -Wreturn-type -Wsign-compare -Wmultichar -Wformat-nonliteral -Winit-self -Wuninitialized -Wno-deprecated -Wformat-security -Werror -Wcomment -Wtrigraphs -Wundef -Wunused-macros -pedantic-errors -std=c99 +C_ARGS = -DIS_NOT_PEBBLE -DRELEASE -pipe -m64 -ansi -fPIC -fPIE -g -Os -ffunction-sections -fno-exceptions -fstack-protector-all -fvisibility=hidden -W -Wall -Wextra -Wunused-parameter -Wunused-function -Wunused-label -Wpointer-arith -Wformat -Wreturn-type -Wsign-compare -Wmultichar -Wformat-nonliteral -Winit-self -Wuninitialized -Wdeprecated -Wformat-security -Werror -Wcomment -Wtrigraphs -Wundef -Wunused-macros -pedantic-errors -std=c99 -fsanitize-undefined-trap-on-error -fsanitize=alignment,bool,bounds,enum,null,return,shift,undefined-trap,unreachable # removed: -lpthread, -Wl,-z,relro -Wl,-z,now CXX_ARGS = -DIS_NOT_PEBBLE -lpthread -pipe -m64 -ansi -fPIC -g -O3 -fno-exceptions -fstack-protector -fvisibility=hidden -W -Wall -Wno-unused-parameter -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wformat -Wreturn-type -Wsign-compare -Wmultichar -Wformat-nonliteral -Winit-self -Wuninitialized -Wno-deprecated -Wformat-security -Wall diff --git a/sample/simple-accelerometer/.gitignore b/sample/simple-accelerometer/.gitignore index 9ed9d4f..f7cd408 100644 --- a/sample/simple-accelerometer/.gitignore +++ b/sample/simple-accelerometer/.gitignore @@ -1,3 +1,5 @@ # Ignore build generated files build + +.lock-waf_linux2_build diff --git a/sample/simple-accelerometer/.lock-waf_linux2_build b/sample/simple-accelerometer/.lock-waf_linux2_build deleted file mode 100644 index aed0a81..0000000 --- a/sample/simple-accelerometer/.lock-waf_linux2_build +++ /dev/null @@ -1,8 +0,0 @@ -argv = ['/home/vagrant/pebble-dev/PebbleSDK-2.0-BETA5/Pebble/waf', 'configure', 'build'] -environ = {'XDG_RUNTIME_DIR': '/run/user/1000', 'LESS': '-R', 'LC_CTYPE': 'en_US.UTF-8', 'SSH_CLIENT': '10.0.2.2 49994 22', 'LSCOLORS': 'Gxfxcxdxbxegedabagacad', 'LOGNAME': 'vagrant', 'USER': 'vagrant', 'PATH': '/home/vagrant/pebble-dev/PebbleSDK-2.0-BETA5/arm-cs-tools/bin:/home/vagrant/bin:/usr/local/bin:/home/vagrant/pebble-dev/PebbleSDK-2.0-BETA5/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games', 'HOME': '/home/vagrant', 'XDG_SESSION_ID': '11', '_': '/home/vagrant/pebble-dev/PebbleSDK-2.0-BETA5/bin/pebble', 'LANG': 'en_US.UTF-8', 'TERM': 'xterm-256color', 'SHELL': '/bin/zsh', 'XDG_SESSION_COOKIE': '16ccae8f6a53e04feed02d6f52cb75dd-1390072954.343424-1847087206', 'SHLVL': '1', 'SSH_TTY': '/dev/pts/1', 'OLDPWD': '/home/vagrant', 'PWD': '/vagrant/mount/code/accel/sample/simple-accelerometer', 'GREP_OPTIONS': '--color=auto', 'MAIL': '/var/mail/vagrant', 'GREP_COLOR': '1;32', 'SSH_CONNECTION': '10.0.2.2 49994 10.0.2.15 22', 'PAGER': 'less'} -files = ['/vagrant/mount/code/accel/sample/simple-accelerometer/wscript'] -hash = -326433459 -options = {'files': '', 'jobs': 1, 'verbose': 0, 'nocache': False, 'progress_bar': 0, 'timestamp': None, 'distcheck_args': None, 'top': '', 'destdir': '', 'keep': 0, 'zones': '', 'debug': False, 'prefix': '/usr/local/', 'download': False, 'force': False, 'targets': '', 'out': ''} -out_dir = '/vagrant/mount/code/accel/sample/simple-accelerometer/build' -run_dir = '/vagrant/mount/code/accel/sample/simple-accelerometer' -top_dir = '/vagrant/mount/code/accel/sample/simple-accelerometer' diff --git a/sample/simple-accelerometer/src/accel.c b/sample/simple-accelerometer/src/accel.c index a55e381..7d787b9 100644 --- a/sample/simple-accelerometer/src/accel.c +++ b/sample/simple-accelerometer/src/accel.c @@ -1,9 +1,3 @@ -#ifndef IS_NOT_PEBBLE -#ifndef PEBBLE -#define PEBBLE -#endif -#endif - #ifdef PEBBLE #include #include @@ -30,7 +24,7 @@ typedef struct { bool is_recorded; int recording_size; - int **normalized_recording; + int32_t **normalized_recording; moving_avg_values **moving_avg_values; int *offsets; @@ -61,7 +55,7 @@ typedef struct internalAccelState { if (INPUT_STATE->state == NULL) { \ return ACCEL_INTERNAL_ERROR; \ } \ - if (INPUT_STATE->dimensions <= 0) { \ + if (INPUT_STATE->dimensions == 0) { \ return ACCEL_INTERNAL_ERROR; \ } \ if (INPUT_STATE->state->window_size <= 0) { \ @@ -88,11 +82,12 @@ typedef struct internalAccelState { // TODO: should we store the offsets as floats instead? #define ALPHA 1.0 -// TODO: include these from a header file? #define MIN(a, b) (((a) < (b)) ? (a) : (b)) // #define MAX(a,b) (((a)>(b))?(a):(b)) -void accel_destroy_gesture(accel_gesture **gesture, int dimensions) { +// TODO: write tests for "internal" functions. + +void accel_destroy_gesture(accel_gesture **gesture, uint32_t dimensions) { if (gesture == NULL || *gesture == NULL) { return; } @@ -100,7 +95,7 @@ void accel_destroy_gesture(accel_gesture **gesture, int dimensions) { accel_gesture *gest = *gesture; if (gest->moving_avg_values != NULL) { - for (int i = 0; i < dimensions; ++i) { + for (uint32_t i = 0; i < dimensions; ++i) { free_moving_avg(&(gest->moving_avg_values[i])); } } @@ -123,11 +118,10 @@ void accel_destroy_gesture(accel_gesture **gesture, int dimensions) { *gesture = NULL; } -int accel_generate_gesture(accel_state *state, accel_gesture **gesture) { +int internal_accel_generate_gesture(accel_state *state, accel_gesture **gesture) { PRECONDITION_VALID_STATE(state); PRECONDITION_NOT_NULL(gesture); - // TODO: write a test for this value. PRECONDITION_NULL((*gesture)); size_t gesture_size = sizeof(accel_gesture); @@ -146,13 +140,13 @@ int accel_generate_gesture(accel_state *state, accel_gesture **gesture) { *gesture = NULL; return ACCEL_MALLOC_ERROR; } - for (int i = 0; i < state->dimensions; ++i) { + for (uint32_t i = 0; i < state->dimensions; ++i) { // TODO: these two shouldn't both be the same.... int result = allocate_moving_avg(state->state->window_size, state->state->window_size, &((*gesture)->moving_avg_values[i])); if (result != ACCEL_SUCCESS) { - for (int j = 0; j < i; ++j) { + for (uint32_t j = 0; j < i; ++j) { free_moving_avg(&((*gesture)->moving_avg_values[i])); } accel_destroy_gesture(gesture, state->dimensions); @@ -162,14 +156,14 @@ int accel_generate_gesture(accel_state *state, accel_gesture **gesture) { return ACCEL_SUCCESS; } -int accel_generate_state(accel_state **state, int dimensions, int window_size, accel_callback callback, +int accel_generate_state(accel_state **state, uint32_t dimensions, int window_size, accel_callback callback, const int threshold) { PRECONDITION_NOT_NULL(state); // TODO: write a test for this value. PRECONDITION_NULL(*state); - if (dimensions <= 0) { + if (dimensions == 0) { return ACCEL_PARAM_ERROR; } if (window_size <= 0) { @@ -208,6 +202,7 @@ int accel_generate_state(accel_state **state, int dimensions, int window_size, a (*state)->dimensions = dimensions; (*state)->state->window_size = window_size > 0 ? window_size : 2; (*state)->state->threshold = threshold; + // TODO: verify that the state we have created is valid. return ACCEL_SUCCESS; } @@ -216,7 +211,7 @@ int accel_destroy_state(accel_state **state) { PRECONDITION_NOT_NULL(state); PRECONDITION_NOT_NULL(*state); - int dimensions = (*state)->dimensions; + uint32_t dimensions = (*state)->dimensions; if ((*state)->state != NULL) { internal_accel_state *istate = (*state)->state; if (istate->gestures != NULL) { @@ -260,7 +255,7 @@ int accel_start_record_gesture(accel_state *state, int *gesture) { state->state->gestures[*gesture] = NULL; - int result = accel_generate_gesture(state, &(state->state->gestures[*gesture])); + int result = internal_accel_generate_gesture(state, &(state->state->gestures[*gesture])); if (result != ACCEL_SUCCESS) { *gesture = -1; if (state->state->num_gestures_saved == 1) { @@ -284,14 +279,14 @@ int accel_start_record_gesture(accel_state *state, int *gesture) { // The uWave paper suggests a mapping from [-20, 20]->[-15, 15], but cube root // should to work better for variable ranges. // TODO: revisit this decision. -int normalize(int sum) { return (int)cbrt(sum); } +int normalize(int32_t sum) { return (int32_t)cbrt(sum); } -int reset_gesture(accel_gesture *gest, const int dimensions) { +int reset_gesture(accel_gesture *gest, const uint32_t dimensions) { PRECONDITION_NOT_NULL(gest); for (int i = 0; i < gest->recording_size; ++i) { gest->offsets[i] = INT16_MAX; } - for (int d = 0; d < dimensions; ++d) { + for (uint32_t d = 0; d < dimensions; ++d) { reset_moving_avg(gest->moving_avg_values[d]); } return ACCEL_SUCCESS; @@ -340,7 +335,7 @@ int accel_end_record_gesture(accel_state *state, int gesture_id) { for (int i = 0; i < gesture->recording_size; ++i) { gesture->offsets[i] = INT16_MAX; } - for (int d = 0; d < state->dimensions; ++d) { + for (uint32_t d = 0; d < state->dimensions; ++d) { reset_moving_avg(gesture->moving_avg_values[d]); } return ACCEL_SUCCESS; @@ -349,23 +344,23 @@ int accel_end_record_gesture(accel_state *state, int gesture_id) { // TODO: gracefully handle malloc failure in this function. // TODO: this should return error types instead of being void. // Follow-up: find usages of this method. -void handle_recording_tick(accel_gesture *gesture, int dimensions) { +void handle_recording_tick(accel_gesture *gesture, uint32_t dimensions) { if (gesture == NULL) { return; } // TODO: grow exponentially, not linearly. Linear growth allocates too frequently. if (gesture->recording_size != 0) { gesture->normalized_recording = - (int **)my_realloc(gesture->normalized_recording, (gesture->recording_size + 1) * sizeof(int *), - gesture->recording_size * sizeof(int *)); + (int32_t **)my_realloc(gesture->normalized_recording, (gesture->recording_size + 1) * sizeof(int32_t *), + gesture->recording_size * sizeof(int32_t *)); if (gesture->normalized_recording == NULL) { return; } } else { - gesture->normalized_recording = (int **)malloc(sizeof(int *)); + gesture->normalized_recording = (int32_t **)malloc(sizeof(int32_t *)); } - gesture->normalized_recording[gesture->recording_size] = (int *)malloc(sizeof(int) * dimensions); - for (int i = 0; i < dimensions; ++i) { + gesture->normalized_recording[gesture->recording_size] = (int32_t *)malloc(sizeof(int32_t) * dimensions); + for (uint32_t i = 0; i < dimensions; ++i) { // TODO: fix this int/float business. // TODO: complain about invalid return values. get_latest_frame_moving_avg(gesture->moving_avg_values[i], @@ -379,7 +374,7 @@ void handle_recording_tick(accel_gesture *gesture, int dimensions) { int handle_evaluation_tick(accel_state *state, accel_gesture *gesture, int gesture_id) { // TODO: load the input at the beginning instead of gesture->recording_size times. PRECONDITION_NOT_NULL(gesture); - int dimensions = state->dimensions; + uint32_t dimensions = state->dimensions; if (gesture->moving_avg_values == NULL || gesture->offsets == NULL) { return ACCEL_INTERNAL_ERROR; @@ -390,9 +385,9 @@ int handle_evaluation_tick(accel_state *state, accel_gesture *gesture, int gestu --i; int cost = 0; - for (int d = 0; d < dimensions; ++d) { + for (uint32_t d = 0; d < dimensions; ++d) { int recording_i_d = gesture->normalized_recording[i][d]; - int input_i_d = 0; + int32_t input_i_d = 0; // TODO: complain about invalid return values. get_latest_frame_moving_avg(gesture->moving_avg_values[d], &input_i_d); input_i_d = normalize(input_i_d); @@ -411,9 +406,9 @@ int handle_evaluation_tick(accel_state *state, accel_gesture *gesture, int gestu } for (i = 1; i < gesture->recording_size; ++i) { int cost = 0; - for (int d = 0; d < dimensions; ++d) { + for (uint32_t d = 0; d < dimensions; ++d) { int recording_i_d = gesture->normalized_recording[i][d]; - int input_i_d = 0; + int32_t input_i_d = 0; // TODO: complain about invalid return values. get_latest_frame_moving_avg(gesture->moving_avg_values[d], &input_i_d); if (recording_i_d > input_i_d) { @@ -464,7 +459,7 @@ int accel_process_timer_tick(accel_state *state, int *accel_data) { // If the moving average is at a final line. bool avg_line = false; int returned = ACCEL_SUCCESS; - for (int d = 0; d < state->dimensions && returned == 0; ++d) { + for (uint32_t d = 0; d < state->dimensions && returned == 0; ++d) { returned = append_to_moving_avg(gesture->moving_avg_values[d], accel_data[d], &avg_line); } if (returned != ACCEL_SUCCESS) { diff --git a/sample/simple-accelerometer/src/accel.h b/sample/simple-accelerometer/src/accel.h index eda1110..819c1c9 100644 --- a/sample/simple-accelerometer/src/accel.h +++ b/sample/simple-accelerometer/src/accel.h @@ -1,11 +1,18 @@ #ifndef ACCEL_H #define ACCEL_H +#ifndef IS_NOT_PEBBLE +#ifndef PEBBLE +#define PEBBLE +#endif +#endif + #ifdef __cplusplus extern "C" { #endif #include +#include #define ACCEL_SUCCESS 0 #define ACCEL_PARAM_ERROR -1 @@ -61,7 +68,7 @@ struct accelState; typedef int (*accel_callback)(struct accelState *state, int gesture_id, int offset_found, bool *reset_gesture); typedef struct accelState { - int dimensions; + uint32_t dimensions; accel_callback callback; struct internalAccelState *state; @@ -84,7 +91,7 @@ typedef struct accelState { * gestures must be before the callback is called. * @return ACCEL_SUCCESS if successful, an error code otherwise. */ -int accel_generate_state(accel_state **state, int dimensions, int window_size, accel_callback callback, +int accel_generate_state(accel_state **state, uint32_t dimensions, int window_size, accel_callback callback, const int threshold); /** diff --git a/sample/simple-accelerometer/src/moving_avg_ticker.c b/sample/simple-accelerometer/src/moving_avg_ticker.c index eb243d7..b3f48d8 100644 --- a/sample/simple-accelerometer/src/moving_avg_ticker.c +++ b/sample/simple-accelerometer/src/moving_avg_ticker.c @@ -8,66 +8,62 @@ return MOVING_AVG_PARAM_ERROR; \ } +// TODO: make this into a macro. int precondition_valid_moving_avg_values(moving_avg_values *input) { PRECONDITION_NOT_NULL(input); if (input->wbuf == NULL) { return MOVING_AVG_INTERNAL_ERROR; } - if (input->wbuf_end < 0) { - return MOVING_AVG_INTERNAL_ERROR; - } - if (input->wbuf_len <= 0) { - return MOVING_AVG_INTERNAL_ERROR; - } - if (input->subtotal_size < 0) { + if (input->wbuf_len == 0) { return MOVING_AVG_INTERNAL_ERROR; } if (input->subtotal_size >= input->max_subtotal_size) { return MOVING_AVG_INTERNAL_ERROR; } - if (input->max_subtotal_size <= 0) { + if (input->max_subtotal_size == 0) { return MOVING_AVG_INTERNAL_ERROR; } - return 0; + return MOVING_AVG_SUCCESS; } -int allocate_moving_avg(int num_wbuf, int subtotal_sizes, moving_avg_values **allocated) { +int allocate_moving_avg(uint32_t num_wbuf, uint32_t subtotal_sizes, moving_avg_values **allocated) { PRECONDITION_NOT_NULL(allocated); if (*allocated != NULL) { return MOVING_AVG_PARAM_ERROR; } - // TODO: use an unsigned int instead. - if (num_wbuf <= 0) { + if (num_wbuf == 0) { return MOVING_AVG_PARAM_ERROR; } - if (subtotal_sizes <= 0) { + if (subtotal_sizes == 0) { return MOVING_AVG_PARAM_ERROR; } - size_t size = sizeof(moving_avg_values); + size_t moving_avg_size = sizeof(moving_avg_values); - *allocated = (moving_avg_values *)malloc(size); + *allocated = (moving_avg_values *)malloc(moving_avg_size); if (allocated == NULL) { return MOVING_AVG_MALLOC_ERROR; } - memset(*allocated, 0, size); - (*allocated)->max_subtotal_size = subtotal_sizes; - int *wbuf = (int *)calloc(num_wbuf, sizeof(int)); + uint32_t *wbuf = (uint32_t *)calloc(num_wbuf, sizeof(uint32_t)); if (wbuf == NULL) { // Run away, fast! free(allocated); *allocated = NULL; return MOVING_AVG_MALLOC_ERROR; } + memset(*allocated, 0, moving_avg_size); + + (*allocated)->max_subtotal_size = subtotal_sizes; + (*allocated)->wbuf = wbuf; (*allocated)->wbuf_len = num_wbuf; - return 0; + return MOVING_AVG_SUCCESS; } int reset_moving_avg(moving_avg_values *reset) { int value = precondition_valid_moving_avg_values(reset); - if (value != 0) { + if (value != MOVING_AVG_SUCCESS) { return value; } @@ -75,22 +71,22 @@ int reset_moving_avg(moving_avg_values *reset) { reset->wbuf_end = reset->wbuf_len - 1; reset->subtotal = 0; reset->subtotal_size = 0; - return 0; + return MOVING_AVG_SUCCESS; } -int append_to_moving_avg(moving_avg_values *value, int appended, bool *is_at_end) { +int append_to_moving_avg(moving_avg_values *value, int32_t appended, bool *is_at_end) { int is_valid_return_value = precondition_valid_moving_avg_values(value); - if (is_valid_return_value != 0) { + if (is_valid_return_value != MOVING_AVG_SUCCESS) { return is_valid_return_value; } PRECONDITION_NOT_NULL(is_at_end); - ++value->subtotal_size; + ++(value->subtotal_size); value->subtotal += appended; if (value->subtotal_size != value->max_subtotal_size) { *is_at_end = false; - return 0; + return MOVING_AVG_SUCCESS; } value->wbuf_end = (value->wbuf_end + 1) % value->wbuf_len; @@ -99,23 +95,24 @@ int append_to_moving_avg(moving_avg_values *value, int appended, bool *is_at_end value->subtotal = 0; value->subtotal_size = 0; *is_at_end = true; - return 0; + return MOVING_AVG_SUCCESS; } -int get_latest_frame_moving_avg(moving_avg_values *value, int *frame) { +int get_latest_frame_moving_avg(moving_avg_values *value, int32_t *frame) { int is_valid_return_value = precondition_valid_moving_avg_values(value); - if (is_valid_return_value != 0) { + if (is_valid_return_value != MOVING_AVG_SUCCESS) { return is_valid_return_value; } PRECONDITION_NOT_NULL(frame); - float sum = 0; - for (int i = 0; i < value->wbuf_len; ++i) { - sum += value->wbuf[i] * 1.0 / value->wbuf_len; + // TODO: this can be cleaned up. + uint64_t sum = 0; + for (uint32_t i = 0; i < value->wbuf_len; ++i) { + sum += value->wbuf[i]; } - *frame = (int)sum; - return 0; + *frame = (int32_t)(sum * 1.0) / value->wbuf_len; + return MOVING_AVG_SUCCESS; } int free_moving_avg(moving_avg_values **value) { @@ -128,5 +125,5 @@ int free_moving_avg(moving_avg_values **value) { } free(*value); *value = NULL; - return 0; + return MOVING_AVG_SUCCESS; } diff --git a/sample/simple-accelerometer/src/moving_avg_ticker.h b/sample/simple-accelerometer/src/moving_avg_ticker.h index 346a9a7..801cb21 100644 --- a/sample/simple-accelerometer/src/moving_avg_ticker.h +++ b/sample/simple-accelerometer/src/moving_avg_ticker.h @@ -5,30 +5,33 @@ extern "C" { #endif +#include + #include "accel.h" +#define MOVING_AVG_SUCCESS ACCEL_SUCCESS #define MOVING_AVG_PARAM_ERROR ACCEL_PARAM_ERROR #define MOVING_AVG_INTERNAL_ERROR ACCEL_INTERNAL_ERROR #define MOVING_AVG_MALLOC_ERROR ACCEL_MALLOC_ERROR typedef struct moving_avg_values { // Circular buffer - int *wbuf; - int wbuf_end; - int wbuf_len; + uint32_t *wbuf; + uint32_t wbuf_end; + uint32_t wbuf_len; - int subtotal; - int subtotal_size; - int max_subtotal_size; + int32_t subtotal; + uint32_t subtotal_size; + uint32_t max_subtotal_size; } moving_avg_values; -int allocate_moving_avg(int num_wbuf, int subtotal_sizes, moving_avg_values **allocated); +int allocate_moving_avg(uint32_t num_wbuf, uint32_t subtotal_sizes, moving_avg_values **allocated); int reset_moving_avg(moving_avg_values *reset); -int append_to_moving_avg(moving_avg_values *value, int appended, bool *isAtEnd); +int append_to_moving_avg(moving_avg_values *value, int32_t appended, bool *isAtEnd); -int get_latest_frame_moving_avg(moving_avg_values *value, int *frame); +int get_latest_frame_moving_avg(moving_avg_values *value, int32_t *frame); int free_moving_avg(moving_avg_values **value); diff --git a/sample/simple-accelerometer/src/pebble_makeup.h b/sample/simple-accelerometer/src/pebble_makeup.h index ee92618..119f49c 100644 --- a/sample/simple-accelerometer/src/pebble_makeup.h +++ b/sample/simple-accelerometer/src/pebble_makeup.h @@ -5,9 +5,17 @@ extern "C" { #endif +// TODO: Refactor and rearrange what goes into this file. + +/** + * This file contains all code required to use the accel library source that is + * not provided by the pebble environment. + */ + #include #include #include +#include void *my_realloc(void *old_ptr, size_t new_size, size_t old_size) { if (new_size == old_size) { diff --git a/sample/simple-accelerometer/src/simple-accelerometer.c b/sample/simple-accelerometer/src/simple-accelerometer.c index ab89790..d968f01 100644 --- a/sample/simple-accelerometer/src/simple-accelerometer.c +++ b/sample/simple-accelerometer/src/simple-accelerometer.c @@ -33,7 +33,7 @@ static void select_click_handler(ClickRecognizerRef recognizer, void *context) { static void up_click_handler(ClickRecognizerRef recognizer, void *context) { if (state == NULL) { - int result = accel_generate_state(&state, 3, 1); + int result = accel_generate_state(&state, 3, 1, NULL, 0); if (result == ACCEL_SUCCESS) { text_layer_set_text(text_layer, "Allocated Successfuly"); } else { diff --git a/src/accel.c b/src/accel.c index a55e381..7d787b9 100644 --- a/src/accel.c +++ b/src/accel.c @@ -1,9 +1,3 @@ -#ifndef IS_NOT_PEBBLE -#ifndef PEBBLE -#define PEBBLE -#endif -#endif - #ifdef PEBBLE #include #include @@ -30,7 +24,7 @@ typedef struct { bool is_recorded; int recording_size; - int **normalized_recording; + int32_t **normalized_recording; moving_avg_values **moving_avg_values; int *offsets; @@ -61,7 +55,7 @@ typedef struct internalAccelState { if (INPUT_STATE->state == NULL) { \ return ACCEL_INTERNAL_ERROR; \ } \ - if (INPUT_STATE->dimensions <= 0) { \ + if (INPUT_STATE->dimensions == 0) { \ return ACCEL_INTERNAL_ERROR; \ } \ if (INPUT_STATE->state->window_size <= 0) { \ @@ -88,11 +82,12 @@ typedef struct internalAccelState { // TODO: should we store the offsets as floats instead? #define ALPHA 1.0 -// TODO: include these from a header file? #define MIN(a, b) (((a) < (b)) ? (a) : (b)) // #define MAX(a,b) (((a)>(b))?(a):(b)) -void accel_destroy_gesture(accel_gesture **gesture, int dimensions) { +// TODO: write tests for "internal" functions. + +void accel_destroy_gesture(accel_gesture **gesture, uint32_t dimensions) { if (gesture == NULL || *gesture == NULL) { return; } @@ -100,7 +95,7 @@ void accel_destroy_gesture(accel_gesture **gesture, int dimensions) { accel_gesture *gest = *gesture; if (gest->moving_avg_values != NULL) { - for (int i = 0; i < dimensions; ++i) { + for (uint32_t i = 0; i < dimensions; ++i) { free_moving_avg(&(gest->moving_avg_values[i])); } } @@ -123,11 +118,10 @@ void accel_destroy_gesture(accel_gesture **gesture, int dimensions) { *gesture = NULL; } -int accel_generate_gesture(accel_state *state, accel_gesture **gesture) { +int internal_accel_generate_gesture(accel_state *state, accel_gesture **gesture) { PRECONDITION_VALID_STATE(state); PRECONDITION_NOT_NULL(gesture); - // TODO: write a test for this value. PRECONDITION_NULL((*gesture)); size_t gesture_size = sizeof(accel_gesture); @@ -146,13 +140,13 @@ int accel_generate_gesture(accel_state *state, accel_gesture **gesture) { *gesture = NULL; return ACCEL_MALLOC_ERROR; } - for (int i = 0; i < state->dimensions; ++i) { + for (uint32_t i = 0; i < state->dimensions; ++i) { // TODO: these two shouldn't both be the same.... int result = allocate_moving_avg(state->state->window_size, state->state->window_size, &((*gesture)->moving_avg_values[i])); if (result != ACCEL_SUCCESS) { - for (int j = 0; j < i; ++j) { + for (uint32_t j = 0; j < i; ++j) { free_moving_avg(&((*gesture)->moving_avg_values[i])); } accel_destroy_gesture(gesture, state->dimensions); @@ -162,14 +156,14 @@ int accel_generate_gesture(accel_state *state, accel_gesture **gesture) { return ACCEL_SUCCESS; } -int accel_generate_state(accel_state **state, int dimensions, int window_size, accel_callback callback, +int accel_generate_state(accel_state **state, uint32_t dimensions, int window_size, accel_callback callback, const int threshold) { PRECONDITION_NOT_NULL(state); // TODO: write a test for this value. PRECONDITION_NULL(*state); - if (dimensions <= 0) { + if (dimensions == 0) { return ACCEL_PARAM_ERROR; } if (window_size <= 0) { @@ -208,6 +202,7 @@ int accel_generate_state(accel_state **state, int dimensions, int window_size, a (*state)->dimensions = dimensions; (*state)->state->window_size = window_size > 0 ? window_size : 2; (*state)->state->threshold = threshold; + // TODO: verify that the state we have created is valid. return ACCEL_SUCCESS; } @@ -216,7 +211,7 @@ int accel_destroy_state(accel_state **state) { PRECONDITION_NOT_NULL(state); PRECONDITION_NOT_NULL(*state); - int dimensions = (*state)->dimensions; + uint32_t dimensions = (*state)->dimensions; if ((*state)->state != NULL) { internal_accel_state *istate = (*state)->state; if (istate->gestures != NULL) { @@ -260,7 +255,7 @@ int accel_start_record_gesture(accel_state *state, int *gesture) { state->state->gestures[*gesture] = NULL; - int result = accel_generate_gesture(state, &(state->state->gestures[*gesture])); + int result = internal_accel_generate_gesture(state, &(state->state->gestures[*gesture])); if (result != ACCEL_SUCCESS) { *gesture = -1; if (state->state->num_gestures_saved == 1) { @@ -284,14 +279,14 @@ int accel_start_record_gesture(accel_state *state, int *gesture) { // The uWave paper suggests a mapping from [-20, 20]->[-15, 15], but cube root // should to work better for variable ranges. // TODO: revisit this decision. -int normalize(int sum) { return (int)cbrt(sum); } +int normalize(int32_t sum) { return (int32_t)cbrt(sum); } -int reset_gesture(accel_gesture *gest, const int dimensions) { +int reset_gesture(accel_gesture *gest, const uint32_t dimensions) { PRECONDITION_NOT_NULL(gest); for (int i = 0; i < gest->recording_size; ++i) { gest->offsets[i] = INT16_MAX; } - for (int d = 0; d < dimensions; ++d) { + for (uint32_t d = 0; d < dimensions; ++d) { reset_moving_avg(gest->moving_avg_values[d]); } return ACCEL_SUCCESS; @@ -340,7 +335,7 @@ int accel_end_record_gesture(accel_state *state, int gesture_id) { for (int i = 0; i < gesture->recording_size; ++i) { gesture->offsets[i] = INT16_MAX; } - for (int d = 0; d < state->dimensions; ++d) { + for (uint32_t d = 0; d < state->dimensions; ++d) { reset_moving_avg(gesture->moving_avg_values[d]); } return ACCEL_SUCCESS; @@ -349,23 +344,23 @@ int accel_end_record_gesture(accel_state *state, int gesture_id) { // TODO: gracefully handle malloc failure in this function. // TODO: this should return error types instead of being void. // Follow-up: find usages of this method. -void handle_recording_tick(accel_gesture *gesture, int dimensions) { +void handle_recording_tick(accel_gesture *gesture, uint32_t dimensions) { if (gesture == NULL) { return; } // TODO: grow exponentially, not linearly. Linear growth allocates too frequently. if (gesture->recording_size != 0) { gesture->normalized_recording = - (int **)my_realloc(gesture->normalized_recording, (gesture->recording_size + 1) * sizeof(int *), - gesture->recording_size * sizeof(int *)); + (int32_t **)my_realloc(gesture->normalized_recording, (gesture->recording_size + 1) * sizeof(int32_t *), + gesture->recording_size * sizeof(int32_t *)); if (gesture->normalized_recording == NULL) { return; } } else { - gesture->normalized_recording = (int **)malloc(sizeof(int *)); + gesture->normalized_recording = (int32_t **)malloc(sizeof(int32_t *)); } - gesture->normalized_recording[gesture->recording_size] = (int *)malloc(sizeof(int) * dimensions); - for (int i = 0; i < dimensions; ++i) { + gesture->normalized_recording[gesture->recording_size] = (int32_t *)malloc(sizeof(int32_t) * dimensions); + for (uint32_t i = 0; i < dimensions; ++i) { // TODO: fix this int/float business. // TODO: complain about invalid return values. get_latest_frame_moving_avg(gesture->moving_avg_values[i], @@ -379,7 +374,7 @@ void handle_recording_tick(accel_gesture *gesture, int dimensions) { int handle_evaluation_tick(accel_state *state, accel_gesture *gesture, int gesture_id) { // TODO: load the input at the beginning instead of gesture->recording_size times. PRECONDITION_NOT_NULL(gesture); - int dimensions = state->dimensions; + uint32_t dimensions = state->dimensions; if (gesture->moving_avg_values == NULL || gesture->offsets == NULL) { return ACCEL_INTERNAL_ERROR; @@ -390,9 +385,9 @@ int handle_evaluation_tick(accel_state *state, accel_gesture *gesture, int gestu --i; int cost = 0; - for (int d = 0; d < dimensions; ++d) { + for (uint32_t d = 0; d < dimensions; ++d) { int recording_i_d = gesture->normalized_recording[i][d]; - int input_i_d = 0; + int32_t input_i_d = 0; // TODO: complain about invalid return values. get_latest_frame_moving_avg(gesture->moving_avg_values[d], &input_i_d); input_i_d = normalize(input_i_d); @@ -411,9 +406,9 @@ int handle_evaluation_tick(accel_state *state, accel_gesture *gesture, int gestu } for (i = 1; i < gesture->recording_size; ++i) { int cost = 0; - for (int d = 0; d < dimensions; ++d) { + for (uint32_t d = 0; d < dimensions; ++d) { int recording_i_d = gesture->normalized_recording[i][d]; - int input_i_d = 0; + int32_t input_i_d = 0; // TODO: complain about invalid return values. get_latest_frame_moving_avg(gesture->moving_avg_values[d], &input_i_d); if (recording_i_d > input_i_d) { @@ -464,7 +459,7 @@ int accel_process_timer_tick(accel_state *state, int *accel_data) { // If the moving average is at a final line. bool avg_line = false; int returned = ACCEL_SUCCESS; - for (int d = 0; d < state->dimensions && returned == 0; ++d) { + for (uint32_t d = 0; d < state->dimensions && returned == 0; ++d) { returned = append_to_moving_avg(gesture->moving_avg_values[d], accel_data[d], &avg_line); } if (returned != ACCEL_SUCCESS) { diff --git a/src/accel.h b/src/accel.h index eda1110..819c1c9 100644 --- a/src/accel.h +++ b/src/accel.h @@ -1,11 +1,18 @@ #ifndef ACCEL_H #define ACCEL_H +#ifndef IS_NOT_PEBBLE +#ifndef PEBBLE +#define PEBBLE +#endif +#endif + #ifdef __cplusplus extern "C" { #endif #include +#include #define ACCEL_SUCCESS 0 #define ACCEL_PARAM_ERROR -1 @@ -61,7 +68,7 @@ struct accelState; typedef int (*accel_callback)(struct accelState *state, int gesture_id, int offset_found, bool *reset_gesture); typedef struct accelState { - int dimensions; + uint32_t dimensions; accel_callback callback; struct internalAccelState *state; @@ -84,7 +91,7 @@ typedef struct accelState { * gestures must be before the callback is called. * @return ACCEL_SUCCESS if successful, an error code otherwise. */ -int accel_generate_state(accel_state **state, int dimensions, int window_size, accel_callback callback, +int accel_generate_state(accel_state **state, uint32_t dimensions, int window_size, accel_callback callback, const int threshold); /** diff --git a/src/moving_avg_ticker.c b/src/moving_avg_ticker.c index eb243d7..b3f48d8 100644 --- a/src/moving_avg_ticker.c +++ b/src/moving_avg_ticker.c @@ -8,66 +8,62 @@ return MOVING_AVG_PARAM_ERROR; \ } +// TODO: make this into a macro. int precondition_valid_moving_avg_values(moving_avg_values *input) { PRECONDITION_NOT_NULL(input); if (input->wbuf == NULL) { return MOVING_AVG_INTERNAL_ERROR; } - if (input->wbuf_end < 0) { - return MOVING_AVG_INTERNAL_ERROR; - } - if (input->wbuf_len <= 0) { - return MOVING_AVG_INTERNAL_ERROR; - } - if (input->subtotal_size < 0) { + if (input->wbuf_len == 0) { return MOVING_AVG_INTERNAL_ERROR; } if (input->subtotal_size >= input->max_subtotal_size) { return MOVING_AVG_INTERNAL_ERROR; } - if (input->max_subtotal_size <= 0) { + if (input->max_subtotal_size == 0) { return MOVING_AVG_INTERNAL_ERROR; } - return 0; + return MOVING_AVG_SUCCESS; } -int allocate_moving_avg(int num_wbuf, int subtotal_sizes, moving_avg_values **allocated) { +int allocate_moving_avg(uint32_t num_wbuf, uint32_t subtotal_sizes, moving_avg_values **allocated) { PRECONDITION_NOT_NULL(allocated); if (*allocated != NULL) { return MOVING_AVG_PARAM_ERROR; } - // TODO: use an unsigned int instead. - if (num_wbuf <= 0) { + if (num_wbuf == 0) { return MOVING_AVG_PARAM_ERROR; } - if (subtotal_sizes <= 0) { + if (subtotal_sizes == 0) { return MOVING_AVG_PARAM_ERROR; } - size_t size = sizeof(moving_avg_values); + size_t moving_avg_size = sizeof(moving_avg_values); - *allocated = (moving_avg_values *)malloc(size); + *allocated = (moving_avg_values *)malloc(moving_avg_size); if (allocated == NULL) { return MOVING_AVG_MALLOC_ERROR; } - memset(*allocated, 0, size); - (*allocated)->max_subtotal_size = subtotal_sizes; - int *wbuf = (int *)calloc(num_wbuf, sizeof(int)); + uint32_t *wbuf = (uint32_t *)calloc(num_wbuf, sizeof(uint32_t)); if (wbuf == NULL) { // Run away, fast! free(allocated); *allocated = NULL; return MOVING_AVG_MALLOC_ERROR; } + memset(*allocated, 0, moving_avg_size); + + (*allocated)->max_subtotal_size = subtotal_sizes; + (*allocated)->wbuf = wbuf; (*allocated)->wbuf_len = num_wbuf; - return 0; + return MOVING_AVG_SUCCESS; } int reset_moving_avg(moving_avg_values *reset) { int value = precondition_valid_moving_avg_values(reset); - if (value != 0) { + if (value != MOVING_AVG_SUCCESS) { return value; } @@ -75,22 +71,22 @@ int reset_moving_avg(moving_avg_values *reset) { reset->wbuf_end = reset->wbuf_len - 1; reset->subtotal = 0; reset->subtotal_size = 0; - return 0; + return MOVING_AVG_SUCCESS; } -int append_to_moving_avg(moving_avg_values *value, int appended, bool *is_at_end) { +int append_to_moving_avg(moving_avg_values *value, int32_t appended, bool *is_at_end) { int is_valid_return_value = precondition_valid_moving_avg_values(value); - if (is_valid_return_value != 0) { + if (is_valid_return_value != MOVING_AVG_SUCCESS) { return is_valid_return_value; } PRECONDITION_NOT_NULL(is_at_end); - ++value->subtotal_size; + ++(value->subtotal_size); value->subtotal += appended; if (value->subtotal_size != value->max_subtotal_size) { *is_at_end = false; - return 0; + return MOVING_AVG_SUCCESS; } value->wbuf_end = (value->wbuf_end + 1) % value->wbuf_len; @@ -99,23 +95,24 @@ int append_to_moving_avg(moving_avg_values *value, int appended, bool *is_at_end value->subtotal = 0; value->subtotal_size = 0; *is_at_end = true; - return 0; + return MOVING_AVG_SUCCESS; } -int get_latest_frame_moving_avg(moving_avg_values *value, int *frame) { +int get_latest_frame_moving_avg(moving_avg_values *value, int32_t *frame) { int is_valid_return_value = precondition_valid_moving_avg_values(value); - if (is_valid_return_value != 0) { + if (is_valid_return_value != MOVING_AVG_SUCCESS) { return is_valid_return_value; } PRECONDITION_NOT_NULL(frame); - float sum = 0; - for (int i = 0; i < value->wbuf_len; ++i) { - sum += value->wbuf[i] * 1.0 / value->wbuf_len; + // TODO: this can be cleaned up. + uint64_t sum = 0; + for (uint32_t i = 0; i < value->wbuf_len; ++i) { + sum += value->wbuf[i]; } - *frame = (int)sum; - return 0; + *frame = (int32_t)(sum * 1.0) / value->wbuf_len; + return MOVING_AVG_SUCCESS; } int free_moving_avg(moving_avg_values **value) { @@ -128,5 +125,5 @@ int free_moving_avg(moving_avg_values **value) { } free(*value); *value = NULL; - return 0; + return MOVING_AVG_SUCCESS; } diff --git a/src/moving_avg_ticker.h b/src/moving_avg_ticker.h index 346a9a7..801cb21 100644 --- a/src/moving_avg_ticker.h +++ b/src/moving_avg_ticker.h @@ -5,30 +5,33 @@ extern "C" { #endif +#include + #include "accel.h" +#define MOVING_AVG_SUCCESS ACCEL_SUCCESS #define MOVING_AVG_PARAM_ERROR ACCEL_PARAM_ERROR #define MOVING_AVG_INTERNAL_ERROR ACCEL_INTERNAL_ERROR #define MOVING_AVG_MALLOC_ERROR ACCEL_MALLOC_ERROR typedef struct moving_avg_values { // Circular buffer - int *wbuf; - int wbuf_end; - int wbuf_len; + uint32_t *wbuf; + uint32_t wbuf_end; + uint32_t wbuf_len; - int subtotal; - int subtotal_size; - int max_subtotal_size; + int32_t subtotal; + uint32_t subtotal_size; + uint32_t max_subtotal_size; } moving_avg_values; -int allocate_moving_avg(int num_wbuf, int subtotal_sizes, moving_avg_values **allocated); +int allocate_moving_avg(uint32_t num_wbuf, uint32_t subtotal_sizes, moving_avg_values **allocated); int reset_moving_avg(moving_avg_values *reset); -int append_to_moving_avg(moving_avg_values *value, int appended, bool *isAtEnd); +int append_to_moving_avg(moving_avg_values *value, int32_t appended, bool *isAtEnd); -int get_latest_frame_moving_avg(moving_avg_values *value, int *frame); +int get_latest_frame_moving_avg(moving_avg_values *value, int32_t *frame); int free_moving_avg(moving_avg_values **value); diff --git a/src/pebble_makeup.h b/src/pebble_makeup.h index ee92618..119f49c 100644 --- a/src/pebble_makeup.h +++ b/src/pebble_makeup.h @@ -5,9 +5,17 @@ extern "C" { #endif +// TODO: Refactor and rearrange what goes into this file. + +/** + * This file contains all code required to use the accel library source that is + * not provided by the pebble environment. + */ + #include #include #include +#include void *my_realloc(void *old_ptr, size_t new_size, size_t old_size) { if (new_size == old_size) { diff --git a/test/main.cc b/test/main.cc index 903abe3..20abd23 100644 --- a/test/main.cc +++ b/test/main.cc @@ -54,10 +54,6 @@ TEST(AccelFuzzTest, generate_state_negative_or_zero_dimensions) { int result = accel_generate_state(&state, 0, 1, NULL, 0); EXPECT_EQ(ACCEL_PARAM_ERROR, result); - // -1 dimension must fail - result = accel_generate_state(&state, -1, 1, NULL, 0); - EXPECT_EQ(ACCEL_PARAM_ERROR, result); - // 1 dimension must succeed. state = NULL; result = accel_generate_state(&state, 1, 1, NULL, 0); @@ -667,15 +663,9 @@ TEST(MovingAvgTicker, InvalidLatestFrameParams) { TEST(MovingAvgTickerFuzzTest, allocate_moving_avg) { moving_avg_values *allocated = NULL; - // Test with negative num_wbuf - EXPECT_EQ(MOVING_AVG_PARAM_ERROR, allocate_moving_avg(-1, 1, &allocated)); - // Test with zero num_wbuf EXPECT_EQ(MOVING_AVG_PARAM_ERROR, allocate_moving_avg(0, 1, &allocated)); - // Test with negative subtotal_size - EXPECT_EQ(MOVING_AVG_PARAM_ERROR, allocate_moving_avg(1, -1, &allocated)); - // Test with zero subtotal_size EXPECT_EQ(MOVING_AVG_PARAM_ERROR, allocate_moving_avg(1, 0, &allocated));