From 18154deef4d3877d3c9c0364a9da631e4e9f7da5 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sat, 31 Aug 2024 08:31:26 -0400 Subject: [PATCH 1/8] Adds a simple calculator face --- movement/make/Makefile | 1 + movement/movement_faces.h | 1 + .../complication/simple_calculator_face.c | 415 ++++++++++++++++++ .../complication/simple_calculator_face.h | 145 ++++++ 4 files changed, 562 insertions(+) create mode 100644 movement/watch_faces/complication/simple_calculator_face.c create mode 100644 movement/watch_faces/complication/simple_calculator_face.h diff --git a/movement/make/Makefile b/movement/make/Makefile index da5486b0..40b5be35 100644 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -129,6 +129,7 @@ SRCS += \ ../watch_faces/clock/minute_repeater_decimal_face.c \ ../watch_faces/complication/tuning_tones_face.c \ ../watch_faces/complication/kitchen_conversions_face.c \ + ../watch_faces/complication/simple_calculator_face.c \ # New watch faces go above this line. # Leave this line at the bottom of the file; it has all the targets for making your project. diff --git a/movement/movement_faces.h b/movement/movement_faces.h index 35571109..55d4124b 100644 --- a/movement/movement_faces.h +++ b/movement/movement_faces.h @@ -104,6 +104,7 @@ #include "minute_repeater_decimal_face.h" #include "tuning_tones_face.h" #include "kitchen_conversions_face.h" +#include "simple_calculator_face.h" // New includes go above this line. #endif // MOVEMENT_FACES_H_ diff --git a/movement/watch_faces/complication/simple_calculator_face.c b/movement/watch_faces/complication/simple_calculator_face.c new file mode 100644 index 00000000..95804ced --- /dev/null +++ b/movement/watch_faces/complication/simple_calculator_face.c @@ -0,0 +1,415 @@ +/* + * MIT License + * + * Copyright (c) 2024 Patrick McGuire + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include "simple_calculator_face.h" + +void simple_calculator_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) { + (void) settings; + (void) watch_face_index; + if (*context_ptr == NULL) { + *context_ptr = malloc(sizeof(simple_calculator_state_t)); + memset(*context_ptr, 0, sizeof(simple_calculator_state_t)); + } +} + +void simple_calculator_face_activate(movement_settings_t *settings, void *context) { + (void) settings; + simple_calculator_state_t *state = (simple_calculator_state_t *)context; + state->placeholder = PLACEHOLDER_ONES; + state->mode = MODE_ENTERING_FIRST_NUM; + movement_request_tick_frequency(4); +} + +static void increment_placeholder(calculator_number_t *number, calculator_placeholder_t placeholder) { + uint8_t *digits[] = { + &number->hundredths, + &number->tenths, + &number->ones, + &number->tens, + &number->hundreds, + &number->thousands + }; + *digits[placeholder] = (*digits[placeholder] + 1) % 10; +} + +static float convert_to_float(calculator_number_t number) { + float result = 0.0; + + // Add the whole number portion + result += number.thousands * 1000.0f; + result += number.hundreds * 100.0f; + result += number.tens * 10.0f; + result += number.ones * 1.0f; + + // Add the fractional portion + result += number.tenths * 0.1f; + result += number.hundredths * 0.01f; + + // Round to nearest hundredth + result = roundf(result * 100) / 100; + return result; +} + +static char* update_display_number(calculator_number_t *number, char *display_string, uint8_t which_num) { + char sign = ' '; + if (number->negative) sign = '-'; + sprintf(display_string, "CA%d%c%d%d%d%d%d%d", + which_num, + sign, + number->thousands, + number->hundreds, + number->tens, + number->ones, + number->tenths, + number->hundredths); + + return display_string; +} + +static void set_operation(simple_calculator_state_t *state) { + switch (state->operation) { + case 0: + watch_display_string(" Add", 0); + break; + case 1: + watch_display_string(" sub", 0); + break; + case 2: + watch_display_string(" n&ul", 0); + break; + case 3: + watch_display_string(" div", 0); + break; + case 4: + watch_display_string(" root", 0); + break; + case 5: + watch_display_string(" pow", 0); + break; + } +} + +static void cycle_operation(simple_calculator_state_t *state) { + state->operation = (state->operation + 1) % OPERATIONS_COUNT; // Assuming there are 6 operations + printf("Current operation: %d\n", state->operation); // For debugging +} + + +static calculator_number_t convert_to_string(float number) { + calculator_number_t result; + + // Handle negative numbers + bool is_negative = (number < 0); + if (is_negative) { + number = -number; + result.negative = true; + } + + int int_part = (int)number; + float decimal_part_float = ((number - int_part) * 100); // two decimal places + printf("decimal_part_float = %f\n", decimal_part_float); //For debugging + int decimal_part = round(decimal_part_float); + printf("decimal_part = %d\n", decimal_part); //For debugging + + result.thousands = int_part / 1000 % 10; + result.hundreds = int_part / 100 % 10; + result.tens = int_part / 10 % 10; + result.ones = int_part % 10; + + result.tenths = decimal_part / 10 % 10; + result.hundredths = decimal_part % 10; + + return result; +} + +static void reset_to_zero(calculator_number_t *number) { + number->negative = false; + number->hundredths = 0; + number->tenths = 0; + number->ones = 0; + number->tens = 0; + number->hundreds = 0; + number->thousands = 0; +} + +static void set_number(calculator_number_t *number, calculator_placeholder_t placeholder, char *display_string, char *temp_display_string, movement_event_t event, uint8_t which_num) { + uint8_t display_index; + // Update display string with current number + update_display_number(number, display_string, which_num); + + // Copy the updated display string to a temporary buffer + strcpy(temp_display_string, display_string); + + // Determine the display index based on the placeholder + display_index = 9 - placeholder; + + // Blink selected placeholder + // Check if `event.subsecond` is even + if (event.subsecond % 2 == 0) { + // Replace the character at the index corresponding to the current placeholder with a space + temp_display_string[display_index] = ' '; + } + + // Display the (possibly modified) string + watch_display_string(temp_display_string, 0); +} + +static void view_results(simple_calculator_state_t *state, char *display_string) { + float first_num_float, second_num_float, result_float = 0.0f; // For arithmetic operations + // Convert the numbers to float + first_num_float = convert_to_float(state->first_num); + if (state->first_num.negative) first_num_float = first_num_float * -1; + printf("first_num_float = %f\n", first_num_float); // For debugging // For debugging + second_num_float = convert_to_float(state->second_num); + if (state->second_num.negative) second_num_float = second_num_float * -1; + printf("second_num_float = %f\n", second_num_float); // For debugging + + // Perform the calculation based on the selected operation + switch (state->operation) { + case OP_ADD: + result_float = first_num_float + second_num_float; + break; + case OP_SUB: + result_float = first_num_float - second_num_float; + break; + case OP_MULT: + result_float = first_num_float * second_num_float; + break; + case OP_DIV: + if (second_num_float != 0) { + result_float = first_num_float / second_num_float; + } else { + state->mode = MODE_ERROR; + return; + } + break; + case OP_ROOT: + if (first_num_float >= 0) { + result_float = sqrtf(first_num_float); + } else { + state->mode = MODE_ERROR; + return; + } + break; + case OP_POWER: + result_float = powf(first_num_float, second_num_float); // Power operation + break; + default: + result_float = 0.0f; + break; + } + + if (result_float > 9999.99 || result_float < -9999.99) { + state->mode = MODE_ERROR; + return; + } + + result_float = roundf(result_float * 100.0f) / 100.0f; // Might not be needed + printf("result as float = %f\n", result_float); // For debugging + + // Convert the float result to a string + state->result = convert_to_string(result_float); + + // Update the display with the result + update_display_number(&state->result, display_string, 3); + watch_display_string(display_string, 0); +} + +static void reset_from_error(simple_calculator_state_t *state) { + reset_to_zero(&state->first_num); + reset_to_zero(&state->second_num); + state->mode = MODE_ENTERING_FIRST_NUM; +} +bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { + simple_calculator_state_t *state = (simple_calculator_state_t *)context; + char display_string[10]; + char temp_display_string[10]; // Temporary buffer for blinking effect + + switch (event.event_type) { + case EVENT_ACTIVATE: + break; + + case EVENT_TICK: + switch (state->mode) { + case MODE_ENTERING_FIRST_NUM: + set_number(&state->first_num, + state->placeholder, + display_string, + temp_display_string, + event, + 1); + break; + + case MODE_CHOOSING: + set_operation(state); + break; + + case MODE_ENTERING_SECOND_NUM: + // If doing a square root calculation, skip to results + if (state->operation == 4) { + state->mode = MODE_VIEW_RESULTS; + // otherwise, set the second number + } else { + set_number(&state->second_num, + state->placeholder, + display_string, + temp_display_string, + event, + 2); + } + break; + + case MODE_VIEW_RESULTS: + view_results(state, display_string); + break; + case MODE_ERROR: + watch_display_string("CA Error ", 0); + break; + } + break; + + case EVENT_LIGHT_BUTTON_DOWN: + break; + + case EVENT_LIGHT_BUTTON_UP: + switch (state->mode) { + case MODE_ENTERING_FIRST_NUM: + case MODE_ENTERING_SECOND_NUM: + // Move to the next placeholder when the light button is pressed + state->placeholder = (state->placeholder + 1) % MAX_PLACEHOLDERS; // Loop back to the start after PLACEHOLDER_THOUSANDS + break; + case MODE_CHOOSING: + cycle_operation(state); + break; + case MODE_ERROR: + reset_from_error(state); + break; + case MODE_VIEW_RESULTS: + break; + } + break; + + case EVENT_LIGHT_LONG_PRESS: + switch (state->mode) { + case MODE_ENTERING_FIRST_NUM: + // toggle negative on state->first_num + state->first_num.negative = !state->first_num.negative; + break; + case MODE_ENTERING_SECOND_NUM: + // toggle negative on state->second_num + state->first_num.negative = !state->first_num.negative; + break; + case MODE_ERROR: + reset_from_error(state); + break; + case MODE_CHOOSING: + case MODE_VIEW_RESULTS: + break; + } + break; + + case EVENT_ALARM_BUTTON_UP: + switch (state->mode) { + case MODE_ENTERING_FIRST_NUM: + // Increment the digit in the current placeholder + increment_placeholder(&state->first_num, state->placeholder); + update_display_number(&state->first_num, display_string, 1); + break; + case MODE_CHOOSING: + // Confirm and select the current operation + printf("Selected operation: %d\n", state->operation); // For debugging + state->mode = MODE_ENTERING_SECOND_NUM; + break; + case MODE_ENTERING_SECOND_NUM: + // Increment the digit in the current placeholder + increment_placeholder(&state->second_num, state->placeholder); + update_display_number(&state->second_num, display_string, 2); + break; + case MODE_ERROR: + reset_from_error(state); + break; + case MODE_VIEW_RESULTS: + break; + } + break; + + case EVENT_ALARM_LONG_PRESS: + switch (state->mode) { + case MODE_ENTERING_FIRST_NUM: + reset_to_zero(&state->first_num); + break; + case MODE_ENTERING_SECOND_NUM: + reset_to_zero(&state->second_num); + break; + case MODE_ERROR: + reset_from_error(state); + break; + case MODE_CHOOSING: + case MODE_VIEW_RESULTS: + break; + } + break; + + case EVENT_MODE_BUTTON_DOWN: + break; + + case EVENT_MODE_BUTTON_UP: + if (state->mode == MODE_ERROR) { + reset_from_error(state); + } else { + state->placeholder = PLACEHOLDER_ONES; + state->mode = (state->mode + 1) % 4; + if (state->mode == MODE_ENTERING_FIRST_NUM) { + state->first_num = state->result; + reset_to_zero(&state->second_num); + } + printf("Current mode: %d\n", state->mode); // For debugging + } + break; + + case EVENT_MODE_LONG_PRESS: + movement_move_to_next_face(); + break; + + case EVENT_TIMEOUT: + movement_request_tick_frequency(1); + movement_move_to_face(0); + break; + + default: + return movement_default_loop_handler(event, settings); + } + + return true; +} + +void simple_calculator_face_resign(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; + movement_request_tick_frequency(1); +} + diff --git a/movement/watch_faces/complication/simple_calculator_face.h b/movement/watch_faces/complication/simple_calculator_face.h new file mode 100644 index 00000000..1f77dc08 --- /dev/null +++ b/movement/watch_faces/complication/simple_calculator_face.h @@ -0,0 +1,145 @@ +/* + * MIT License + * + * Copyright (c) 2024 Patrick McGuire + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef SIMPLE_CALCULATOR_FACE_H_ +#define SIMPLE_CALCULATOR_FACE_H_ + +#include "movement.h" + +/* + * Simple Calculator + * + * How to use: + * + * Flow: + * Enter first number -> Select operator -> Enter second number -> View Results + * + * How to read the display: + * - "CA" is displayed at the top to tell you that you're in the CAlculator + * - The top-right digit (1, 2, or 3) lets you know whether you're entering the + * first number (1), entering the second number (2), or viewing the results (3). + * - To the right of the top-right digit will show the number's sign. If the + * number is negative, a "-" will be displayed, otherwise it is empty. + * - The 4 large digits to the left are whole numbers and the 2 smaller digits + * on the right are the tenths and hundredths decimal places. + * + * Entering the first number: + * - Press ALARM to increment the selected (blinking) digit + * - Press LIGHT to move to the next placeholder + * - LONG PRESS the LIGHT button to toggle the number's sign to make it + * negative + * - LONG PRESS the ALARM button to reset the number to 0 + * - Press MODE to proceed to selecting the operator + * + * Selecting the operator: + * - Press the LIGHT button to cycle through available operators. They are: + * + Add + * - Subtract + * * Multiply + * / Divide + * sqrtf() Square root + * powf() Power (exponent calculation) + * - Press MODE or ALARM to proceed to entering the second number + * + * Entering the second number: + * - Everything is the same as setting the first number except that pressing + * MODE here will proceed to viewing the results + * + * Viewing the results: + * - Pressing MODE will start a new calculation with the result as the first + * number. (LONG PRESS ALARM to reset the value to 0) + * + * Errors: + * - An error will be triggered if the result is not able to be displayed, that + * is, if the value is greater than 9,999.99 or less than -9,999.99. + * - An error will also be triggered if an impossible operation is selected, + * for instance trying to divide by 0 or get the square root of a negative + * number. + * - Exit error mode and start over with any button press. + * + */ + +#define OPERATIONS_COUNT 6 +#define MAX_PLACEHOLDERS 6 + +typedef struct { + bool negative; + uint8_t hundredths; + uint8_t tenths; + uint8_t ones; + uint8_t tens; + uint8_t hundreds; + uint8_t thousands; +} calculator_number_t; + +typedef enum { + PLACEHOLDER_HUNDREDTHS, + PLACEHOLDER_TENTHS, + PLACEHOLDER_ONES, + PLACEHOLDER_TENS, + PLACEHOLDER_HUNDREDS, + PLACEHOLDER_THOUSANDS +} calculator_placeholder_t; + +typedef enum { + OP_ADD, + OP_SUB, + OP_MULT, + OP_DIV, + OP_ROOT, + OP_POWER, +} calculator_operation_t; + +typedef enum { + MODE_ENTERING_FIRST_NUM, + MODE_CHOOSING, + MODE_ENTERING_SECOND_NUM, + MODE_VIEW_RESULTS, + MODE_ERROR +} calculator_mode_t; + +typedef struct { + calculator_number_t first_num; + calculator_number_t second_num; + calculator_number_t result; + calculator_operation_t operation; + calculator_mode_t mode; + calculator_placeholder_t placeholder; +} simple_calculator_state_t; + +void simple_calculator_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr); +void simple_calculator_face_activate(movement_settings_t *settings, void *context); +bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void simple_calculator_face_resign(movement_settings_t *settings, void *context); + +#define simple_calculator_face ((const watch_face_t){ \ + simple_calculator_face_setup, \ + simple_calculator_face_activate, \ + simple_calculator_face_loop, \ + simple_calculator_face_resign, \ + NULL, \ +}) + +#endif // SIMPLE_CALCULATOR_FACE_H_ + From 28db77f90c0ff21fa9657039ab69f427e91fc99d Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sat, 31 Aug 2024 08:36:02 -0400 Subject: [PATCH 2/8] forgot to mention long press MODE for next face --- movement/watch_faces/complication/simple_calculator_face.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/movement/watch_faces/complication/simple_calculator_face.h b/movement/watch_faces/complication/simple_calculator_face.h index 1f77dc08..4f1e8d5a 100644 --- a/movement/watch_faces/complication/simple_calculator_face.h +++ b/movement/watch_faces/complication/simple_calculator_face.h @@ -32,6 +32,8 @@ * * How to use: * + * Important note: LONG PRESS MODE to move to next watch face + * * Flow: * Enter first number -> Select operator -> Enter second number -> View Results * From e13d42b5b5d1234293e67d162affb6499956b180 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sat, 31 Aug 2024 12:41:57 -0400 Subject: [PATCH 3/8] mode=movement_move_to_next_face & longmode = face0 --- .../watch_faces/complication/simple_calculator_face.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/movement/watch_faces/complication/simple_calculator_face.c b/movement/watch_faces/complication/simple_calculator_face.c index 95804ced..ada289df 100644 --- a/movement/watch_faces/complication/simple_calculator_face.c +++ b/movement/watch_faces/complication/simple_calculator_face.c @@ -380,6 +380,14 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se case EVENT_MODE_BUTTON_UP: if (state->mode == MODE_ERROR) { reset_from_error(state); + } else if (state->mode == MODE_ENTERING_FIRST_NUM && + state->first_num.hundredths == 0 && + state->first_num.tenths == 0 && + state->first_num.ones== 0 && + state->first_num.tens == 0 && + state->first_num.hundreds == 0 && + state->first_num.thousands == 0) { + movement_move_to_next_face(); } else { state->placeholder = PLACEHOLDER_ONES; state->mode = (state->mode + 1) % 4; @@ -392,7 +400,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se break; case EVENT_MODE_LONG_PRESS: - movement_move_to_next_face(); + movement_move_to_face(0); break; case EVENT_TIMEOUT: From b607b6f7a9177f3fc7e16d842f0b7f6f18a86d9e Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sat, 31 Aug 2024 12:44:29 -0400 Subject: [PATCH 4/8] removed note about mode long press --- movement/watch_faces/complication/simple_calculator_face.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/movement/watch_faces/complication/simple_calculator_face.h b/movement/watch_faces/complication/simple_calculator_face.h index 4f1e8d5a..1f77dc08 100644 --- a/movement/watch_faces/complication/simple_calculator_face.h +++ b/movement/watch_faces/complication/simple_calculator_face.h @@ -32,8 +32,6 @@ * * How to use: * - * Important note: LONG PRESS MODE to move to next watch face - * * Flow: * Enter first number -> Select operator -> Enter second number -> View Results * From c75a21196f088064d0763d07065df076311e940c Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sat, 31 Aug 2024 14:46:23 -0400 Subject: [PATCH 5/8] commented out debugging printf() statements --- .../complication/simple_calculator_face.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/movement/watch_faces/complication/simple_calculator_face.c b/movement/watch_faces/complication/simple_calculator_face.c index ada289df..3221981c 100644 --- a/movement/watch_faces/complication/simple_calculator_face.c +++ b/movement/watch_faces/complication/simple_calculator_face.c @@ -115,7 +115,7 @@ static void set_operation(simple_calculator_state_t *state) { static void cycle_operation(simple_calculator_state_t *state) { state->operation = (state->operation + 1) % OPERATIONS_COUNT; // Assuming there are 6 operations - printf("Current operation: %d\n", state->operation); // For debugging + //printf("Current operation: %d\n", state->operation); // For debugging } @@ -131,9 +131,9 @@ static calculator_number_t convert_to_string(float number) { int int_part = (int)number; float decimal_part_float = ((number - int_part) * 100); // two decimal places - printf("decimal_part_float = %f\n", decimal_part_float); //For debugging + //printf("decimal_part_float = %f\n", decimal_part_float); //For debugging int decimal_part = round(decimal_part_float); - printf("decimal_part = %d\n", decimal_part); //For debugging + //printf("decimal_part = %d\n", decimal_part); //For debugging result.thousands = int_part / 1000 % 10; result.hundreds = int_part / 100 % 10; @@ -183,10 +183,10 @@ static void view_results(simple_calculator_state_t *state, char *display_string) // Convert the numbers to float first_num_float = convert_to_float(state->first_num); if (state->first_num.negative) first_num_float = first_num_float * -1; - printf("first_num_float = %f\n", first_num_float); // For debugging // For debugging + //printf("first_num_float = %f\n", first_num_float); // For debugging // For debugging second_num_float = convert_to_float(state->second_num); if (state->second_num.negative) second_num_float = second_num_float * -1; - printf("second_num_float = %f\n", second_num_float); // For debugging + //printf("second_num_float = %f\n", second_num_float); // For debugging // Perform the calculation based on the selected operation switch (state->operation) { @@ -229,7 +229,7 @@ static void view_results(simple_calculator_state_t *state, char *display_string) } result_float = roundf(result_float * 100.0f) / 100.0f; // Might not be needed - printf("result as float = %f\n", result_float); // For debugging + //printf("result as float = %f\n", result_float); // For debugging // Convert the float result to a string state->result = convert_to_string(result_float); @@ -341,7 +341,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se break; case MODE_CHOOSING: // Confirm and select the current operation - printf("Selected operation: %d\n", state->operation); // For debugging + //printf("Selected operation: %d\n", state->operation); // For debugging state->mode = MODE_ENTERING_SECOND_NUM; break; case MODE_ENTERING_SECOND_NUM: @@ -395,7 +395,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se state->first_num = state->result; reset_to_zero(&state->second_num); } - printf("Current mode: %d\n", state->mode); // For debugging + //printf("Current mode: %d\n", state->mode); // For debugging } break; From 70426751f85e9986b063b73aa8aa792b9773329b Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sat, 31 Aug 2024 17:47:15 -0400 Subject: [PATCH 6/8] negative toggle was only for first_num -- fixed --- movement/watch_faces/complication/simple_calculator_face.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/movement/watch_faces/complication/simple_calculator_face.c b/movement/watch_faces/complication/simple_calculator_face.c index 95804ced..3542590d 100644 --- a/movement/watch_faces/complication/simple_calculator_face.c +++ b/movement/watch_faces/complication/simple_calculator_face.c @@ -321,7 +321,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se break; case MODE_ENTERING_SECOND_NUM: // toggle negative on state->second_num - state->first_num.negative = !state->first_num.negative; + state->second_num.negative = !state->second_num.negative; break; case MODE_ERROR: reset_from_error(state); From 12b1432aae00a698665320289a00d2035dee845c Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sun, 1 Sep 2024 10:10:59 -0400 Subject: [PATCH 7/8] mode long press = reset_all() --- .../complication/simple_calculator_face.c | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/movement/watch_faces/complication/simple_calculator_face.c b/movement/watch_faces/complication/simple_calculator_face.c index 0623525a..b3b2d0e6 100644 --- a/movement/watch_faces/complication/simple_calculator_face.c +++ b/movement/watch_faces/complication/simple_calculator_face.c @@ -92,22 +92,22 @@ static char* update_display_number(calculator_number_t *number, char *display_st static void set_operation(simple_calculator_state_t *state) { switch (state->operation) { - case 0: + case OP_ADD: watch_display_string(" Add", 0); break; - case 1: + case OP_SUB: watch_display_string(" sub", 0); break; - case 2: + case OP_MULT: watch_display_string(" n&ul", 0); break; - case 3: + case OP_DIV: watch_display_string(" div", 0); break; - case 4: + case OP_ROOT: watch_display_string(" root", 0); break; - case 5: + case OP_POWER: watch_display_string(" pow", 0); break; } @@ -239,10 +239,12 @@ static void view_results(simple_calculator_state_t *state, char *display_string) watch_display_string(display_string, 0); } -static void reset_from_error(simple_calculator_state_t *state) { +static void reset_all(simple_calculator_state_t *state) { reset_to_zero(&state->first_num); reset_to_zero(&state->second_num); state->mode = MODE_ENTERING_FIRST_NUM; + state->operation = OP_ADD; + state->placeholder = PLACEHOLDER_ONES; } bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { simple_calculator_state_t *state = (simple_calculator_state_t *)context; @@ -270,7 +272,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se case MODE_ENTERING_SECOND_NUM: // If doing a square root calculation, skip to results - if (state->operation == 4) { + if (state->operation == OP_ROOT) { state->mode = MODE_VIEW_RESULTS; // otherwise, set the second number } else { @@ -306,7 +308,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se cycle_operation(state); break; case MODE_ERROR: - reset_from_error(state); + reset_all(state); break; case MODE_VIEW_RESULTS: break; @@ -324,7 +326,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se state->second_num.negative = !state->second_num.negative; break; case MODE_ERROR: - reset_from_error(state); + reset_all(state); break; case MODE_CHOOSING: case MODE_VIEW_RESULTS: @@ -350,7 +352,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se update_display_number(&state->second_num, display_string, 2); break; case MODE_ERROR: - reset_from_error(state); + reset_all(state); break; case MODE_VIEW_RESULTS: break; @@ -366,7 +368,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se reset_to_zero(&state->second_num); break; case MODE_ERROR: - reset_from_error(state); + reset_all(state); break; case MODE_CHOOSING: case MODE_VIEW_RESULTS: @@ -379,7 +381,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se case EVENT_MODE_BUTTON_UP: if (state->mode == MODE_ERROR) { - reset_from_error(state); + reset_all(state); } else if (state->mode == MODE_ENTERING_FIRST_NUM && state->first_num.hundredths == 0 && state->first_num.tenths == 0 && @@ -400,7 +402,22 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se break; case EVENT_MODE_LONG_PRESS: - movement_move_to_face(0); + if (state->first_num.hundredths == 0 && + state->first_num.tenths == 0 && + state->first_num.ones== 0 && + state->first_num.tens == 0 && + state->first_num.hundreds == 0 && + state->first_num.thousands == 0 && + state->second_num.hundredths == 0 && + state->second_num.tenths == 0 && + state->second_num.ones== 0 && + state->second_num.tens == 0 && + state->second_num.hundreds == 0 && + state->second_num.thousands == 0) { + movement_move_to_face(0); + } else { + reset_all(state); + } break; case EVENT_TIMEOUT: From b774900ae62c6ed7442eec71d0327a81a7da3ed9 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Mon, 2 Sep 2024 13:10:26 -0400 Subject: [PATCH 8/8] finally squashed the bug --- .../complication/simple_calculator_face.c | 95 ++++++++++++------- 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/movement/watch_faces/complication/simple_calculator_face.c b/movement/watch_faces/complication/simple_calculator_face.c index b3b2d0e6..6bfd9e86 100644 --- a/movement/watch_faces/complication/simple_calculator_face.c +++ b/movement/watch_faces/complication/simple_calculator_face.c @@ -36,11 +36,23 @@ void simple_calculator_face_setup(movement_settings_t *settings, uint8_t watch_f } } +static void reset_to_zero(calculator_number_t *number) { + number->negative = false; + number->hundredths = 0; + number->tenths = 0; + number->ones = 0; + number->tens = 0; + number->hundreds = 0; + number->thousands = 0; +} + void simple_calculator_face_activate(movement_settings_t *settings, void *context) { (void) settings; simple_calculator_state_t *state = (simple_calculator_state_t *)context; state->placeholder = PLACEHOLDER_ONES; state->mode = MODE_ENTERING_FIRST_NUM; + reset_to_zero(&state->second_num); + reset_to_zero(&state->result); movement_request_tick_frequency(4); } @@ -71,12 +83,18 @@ static float convert_to_float(calculator_number_t number) { // Round to nearest hundredth result = roundf(result * 100) / 100; + + // Handle negative numbers + if (number.negative) result = -result; + //printf("convert_to_float results = %f\n", result); // For debugging + return result; } static char* update_display_number(calculator_number_t *number, char *display_string, uint8_t which_num) { char sign = ' '; if (number->negative) sign = '-'; + sprintf(display_string, "CA%d%c%d%d%d%d%d%d", which_num, sign, @@ -115,7 +133,6 @@ static void set_operation(simple_calculator_state_t *state) { static void cycle_operation(simple_calculator_state_t *state) { state->operation = (state->operation + 1) % OPERATIONS_COUNT; // Assuming there are 6 operations - //printf("Current operation: %d\n", state->operation); // For debugging } @@ -123,15 +140,17 @@ static calculator_number_t convert_to_string(float number) { calculator_number_t result; // Handle negative numbers - bool is_negative = (number < 0); - if (is_negative) { + if (number < 0) { number = -number; result.negative = true; - } + } else result.negative = false; + // Get each digit from each placeholder int int_part = (int)number; + float decimal_part_float = ((number - int_part) * 100); // two decimal places //printf("decimal_part_float = %f\n", decimal_part_float); //For debugging + int decimal_part = round(decimal_part_float); //printf("decimal_part = %d\n", decimal_part); //For debugging @@ -146,22 +165,15 @@ static calculator_number_t convert_to_string(float number) { return result; } -static void reset_to_zero(calculator_number_t *number) { - number->negative = false; - number->hundredths = 0; - number->tenths = 0; - number->ones = 0; - number->tens = 0; - number->hundreds = 0; - number->thousands = 0; -} - +// This is the main function for setting the first_num and second_num +// WISH: there must be a way to pass less to this function? static void set_number(calculator_number_t *number, calculator_placeholder_t placeholder, char *display_string, char *temp_display_string, movement_event_t event, uint8_t which_num) { + + // Create the display index uint8_t display_index; - // Update display string with current number + + // Update display string with current number and copy into temp string update_display_number(number, display_string, which_num); - - // Copy the updated display string to a temporary buffer strcpy(temp_display_string, display_string); // Determine the display index based on the placeholder @@ -179,14 +191,13 @@ static void set_number(calculator_number_t *number, calculator_placeholder_t pla } static void view_results(simple_calculator_state_t *state, char *display_string) { - float first_num_float, second_num_float, result_float = 0.0f; // For arithmetic operations - // Convert the numbers to float + + // Initialize float variables to do the math + float first_num_float, second_num_float, result_float = 0.0f; + + // Convert the passed numbers to floats first_num_float = convert_to_float(state->first_num); - if (state->first_num.negative) first_num_float = first_num_float * -1; - //printf("first_num_float = %f\n", first_num_float); // For debugging // For debugging second_num_float = convert_to_float(state->second_num); - if (state->second_num.negative) second_num_float = second_num_float * -1; - //printf("second_num_float = %f\n", second_num_float); // For debugging // Perform the calculation based on the selected operation switch (state->operation) { @@ -216,29 +227,37 @@ static void view_results(simple_calculator_state_t *state, char *display_string) } break; case OP_POWER: - result_float = powf(first_num_float, second_num_float); // Power operation + result_float = powf(first_num_float, second_num_float); break; default: result_float = 0.0f; break; } + // Be sure the result can fit on the watch display, else error if (result_float > 9999.99 || result_float < -9999.99) { state->mode = MODE_ERROR; return; } result_float = roundf(result_float * 100.0f) / 100.0f; // Might not be needed + //printf("result as float = %f\n", result_float); // For debugging // Convert the float result to a string + // This isn't strictly necessary, but allows easily reusing the result as + // the next calculation's first_num state->result = convert_to_string(result_float); // Update the display with the result update_display_number(&state->result, display_string, 3); + + //printf("display_string = %s\n", display_string); // For debugging + watch_display_string(display_string, 0); } +// Used both when returning from errors and when long pressing MODE static void reset_all(simple_calculator_state_t *state) { reset_to_zero(&state->first_num); reset_to_zero(&state->second_num); @@ -246,6 +265,7 @@ static void reset_all(simple_calculator_state_t *state) { state->operation = OP_ADD; state->placeholder = PLACEHOLDER_ONES; } + bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { simple_calculator_state_t *state = (simple_calculator_state_t *)context; char display_string[10]; @@ -258,6 +278,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se case EVENT_TICK: switch (state->mode) { case MODE_ENTERING_FIRST_NUM: + // See the WISH for this function above set_number(&state->first_num, state->placeholder, display_string, @@ -274,8 +295,8 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se // If doing a square root calculation, skip to results if (state->operation == OP_ROOT) { state->mode = MODE_VIEW_RESULTS; - // otherwise, set the second number } else { + // See the WISH for this function above set_number(&state->second_num, state->placeholder, display_string, @@ -288,6 +309,7 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se case MODE_VIEW_RESULTS: view_results(state, display_string); break; + case MODE_ERROR: watch_display_string("CA Error ", 0); break; @@ -340,16 +362,21 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se // Increment the digit in the current placeholder increment_placeholder(&state->first_num, state->placeholder); update_display_number(&state->first_num, display_string, 1); + + //printf("display_string = %s\n", display_string); // For debugging + break; case MODE_CHOOSING: // Confirm and select the current operation - //printf("Selected operation: %d\n", state->operation); // For debugging state->mode = MODE_ENTERING_SECOND_NUM; break; case MODE_ENTERING_SECOND_NUM: // Increment the digit in the current placeholder increment_placeholder(&state->second_num, state->placeholder); update_display_number(&state->second_num, display_string, 2); + + //printf("display_string = %s\n", display_string); // For debugging + break; case MODE_ERROR: reset_all(state); @@ -391,30 +418,30 @@ bool simple_calculator_face_loop(movement_event_t event, movement_settings_t *se state->first_num.thousands == 0) { movement_move_to_next_face(); } else { + // Reset the placeholder and proceed to the next MODE state->placeholder = PLACEHOLDER_ONES; state->mode = (state->mode + 1) % 4; + // When looping back to MODE_ENTERING_FIRST_NUM, reuse the + // previous calculation's results as the next calculation's + // first_num; also reset other numbers if (state->mode == MODE_ENTERING_FIRST_NUM) { state->first_num = state->result; reset_to_zero(&state->second_num); + reset_to_zero(&state->result); } - //printf("Current mode: %d\n", state->mode); // For debugging } break; case EVENT_MODE_LONG_PRESS: + // Move to next face if first number is 0 if (state->first_num.hundredths == 0 && state->first_num.tenths == 0 && state->first_num.ones== 0 && state->first_num.tens == 0 && state->first_num.hundreds == 0 && - state->first_num.thousands == 0 && - state->second_num.hundredths == 0 && - state->second_num.tenths == 0 && - state->second_num.ones== 0 && - state->second_num.tens == 0 && - state->second_num.hundreds == 0 && - state->second_num.thousands == 0) { + state->first_num.thousands == 0) { movement_move_to_face(0); + // otherwise, start over } else { reset_all(state); }