diff --git a/make.mk b/make.mk index bb2d153..00933d0 100644 --- a/make.mk +++ b/make.mk @@ -213,6 +213,12 @@ ifndef COLOR $(error Set the COLOR variable to RED, BLUE, or GREEN depending on what board you have.) endif +COLOR_VALID := $(filter $(COLOR),RED BLUE GREEN) + +ifeq ($(COLOR_VALID),) +$(error COLOR must be RED, BLUE, or GREEN) +endif + ifeq ($(COLOR), BLUE) CFLAGS += -DWATCH_IS_BLUE_BOARD endif diff --git a/movement/watch_faces/complication/simon_face.c b/movement/watch_faces/complication/simon_face.c index 99fc160..eb08f17 100644 --- a/movement/watch_faces/complication/simon_face.c +++ b/movement/watch_faces/complication/simon_face.c @@ -33,6 +33,10 @@ #endif static char _simon_display_buf[12]; +static uint8_t _timer; +static uint16_t _delay_beep; +static uint16_t _timeout; +static uint8_t _secSub; static inline uint8_t _simon_get_rand_num(uint8_t num_values) { #if __EMSCRIPTEN__ @@ -55,7 +59,26 @@ static void _simon_not_playing_display(simon_state_t *state) { _simon_clear_display(state); sprintf(_simon_display_buf, "SI %d", state->best_score); + if (!state->soundOff) + watch_set_indicator(WATCH_INDICATOR_BELL); + else + watch_clear_indicator(WATCH_INDICATOR_BELL); + if (!state->lightOff) + watch_set_indicator(WATCH_INDICATOR_SIGNAL); + else + watch_clear_indicator(WATCH_INDICATOR_SIGNAL); watch_display_string(_simon_display_buf, 0); + switch (state->mode) + { + case SIMON_MODE_EASY: + watch_display_string("E", 9); + break; + case SIMON_MODE_HARD: + watch_display_string("H", 9); + break; + default: + break; + } } static void _simon_reset(simon_state_t *state) { @@ -91,19 +114,31 @@ static void _simon_play_note(SimonNote note, simon_state_t *state, bool skip_res _simon_display_note(note, state); switch (note) { case SIMON_LED_NOTE: - watch_set_led_yellow(); - watch_buzzer_play_note(BUZZER_NOTE_D3, 300); + if (!state->lightOff) watch_set_led_yellow(); + if (state->soundOff) + delay_ms(_delay_beep); + else + watch_buzzer_play_note(BUZZER_NOTE_D3, _delay_beep); break; case SIMON_MODE_NOTE: - watch_set_led_red(); - watch_buzzer_play_note(BUZZER_NOTE_E4, 300); + if (!state->lightOff) watch_set_led_red(); + if (state->soundOff) + delay_ms(_delay_beep); + else + watch_buzzer_play_note(BUZZER_NOTE_E4, _delay_beep); break; case SIMON_ALARM_NOTE: - watch_set_led_green(); - watch_buzzer_play_note(BUZZER_NOTE_C3, 300); + if (!state->lightOff) watch_set_led_green(); + if (state->soundOff) + delay_ms(_delay_beep); + else + watch_buzzer_play_note(BUZZER_NOTE_C3, _delay_beep); break; case SIMON_WRONG_NOTE: - watch_buzzer_play_note(BUZZER_NOTE_A1, 800); + if (state->soundOff) + delay_ms(800); + else + watch_buzzer_play_note(BUZZER_NOTE_A1, 800); break; } watch_set_led_off(); @@ -111,7 +146,7 @@ static void _simon_play_note(SimonNote note, simon_state_t *state, bool skip_res if (note != SIMON_WRONG_NOTE) { _simon_clear_display(state); if (!skip_rest) { - watch_buzzer_play_note(BUZZER_NOTE_REST, 200); + watch_buzzer_play_note(BUZZER_NOTE_REST, (_delay_beep * 2)/3); } } } @@ -134,6 +169,7 @@ static void _simon_listen(SimonNote note, simon_state_t *state) { if (state->sequence[state->listen_index] == note) { _simon_play_note(note, state, true); state->listen_index++; + _timer = 0; if (state->listen_index == state->sequence_length) { state->playing_state = SIMON_READY_FOR_NEXT_NOTE; @@ -149,6 +185,22 @@ static void _simon_begin_listening(simon_state_t *state) { state->listen_index = 0; } +static void _simon_change_speed(simon_state_t *state){ + switch (state->mode) + { + case SIMON_MODE_HARD: + _delay_beep = DELAY_FOR_TONE_MS / 2; + _secSub = SIMON_FACE_FREQUENCY / 2; + _timeout = (TIMER_MAX * SIMON_FACE_FREQUENCY) / 2; + break; + default: + _delay_beep = DELAY_FOR_TONE_MS; + _secSub = SIMON_FACE_FREQUENCY; + _timeout = TIMER_MAX * SIMON_FACE_FREQUENCY; + break; + } +} + void simon_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void **context_ptr) { (void)settings; @@ -171,6 +223,10 @@ void simon_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void simon_face_activate(movement_settings_t *settings, void *context) { (void) settings; (void) context; + simon_state_t *state = (simon_state_t *)context; + _simon_change_speed(state); + movement_request_tick_frequency(SIMON_FACE_FREQUENCY); + _timer = 0; } bool simon_face_loop(movement_event_t event, movement_settings_t *settings, @@ -183,9 +239,16 @@ bool simon_face_loop(movement_event_t event, movement_settings_t *settings, _simon_reset(state); break; case EVENT_TICK: - if (state->playing_state == SIMON_READY_FOR_NEXT_NOTE) { - _simon_setup_next_note(state); - } else if (state->playing_state == SIMON_TEACHING) { + if (state->playing_state == SIMON_LISTENING_BACK && state->mode != SIMON_MODE_EASY) + { + _timer++; + if(_timer >= (_timeout)){ + _timer = 0; + _simon_play_note(SIMON_WRONG_NOTE, state, true); + _simon_reset(state); + } + } + else if (state->playing_state == SIMON_TEACHING && event.subsecond == 0) { SimonNote note = state->sequence[state->teaching_index]; // if this is the final note in the sequence, don't play the rest to let // the player jump in faster @@ -196,12 +259,32 @@ bool simon_face_loop(movement_event_t event, movement_settings_t *settings, _simon_begin_listening(state); } } + else if (state->playing_state == SIMON_READY_FOR_NEXT_NOTE && (event.subsecond % _secSub) == 0) { + _timer = 0; + _simon_setup_next_note(state); + } break; case EVENT_LIGHT_BUTTON_DOWN: break; + case EVENT_LIGHT_LONG_PRESS: + if (state->playing_state == SIMON_NOT_PLAYING) { + state->lightOff = !state->lightOff; + _simon_not_playing_display(state); + } + break; + case EVENT_ALARM_LONG_PRESS: + if (state->playing_state == SIMON_NOT_PLAYING) { + state->soundOff = !state->soundOff; + _simon_not_playing_display(state); + if (!state->soundOff) + watch_buzzer_play_note(BUZZER_NOTE_D3, _delay_beep); + } + break; case EVENT_LIGHT_BUTTON_UP: if (state->playing_state == SIMON_NOT_PLAYING) { state->sequence_length = 0; + watch_clear_indicator(WATCH_INDICATOR_BELL); + watch_clear_indicator(WATCH_INDICATOR_SIGNAL); _simon_setup_next_note(state); } else if (state->playing_state == SIMON_LISTENING_BACK) { _simon_listen(SIMON_LED_NOTE, state); @@ -226,6 +309,11 @@ bool simon_face_loop(movement_event_t event, movement_settings_t *settings, if (state->playing_state == SIMON_LISTENING_BACK) { _simon_listen(SIMON_ALARM_NOTE, state); } + else if (state->playing_state == SIMON_NOT_PLAYING){ + state->mode = (state->mode + 1) % SIMON_MODE_TOTAL; + _simon_change_speed(state); + _simon_not_playing_display(state); + } break; case EVENT_TIMEOUT: movement_move_to_face(0); diff --git a/movement/watch_faces/complication/simon_face.h b/movement/watch_faces/complication/simon_face.h index b59d56c..44bc9f3 100644 --- a/movement/watch_faces/complication/simon_face.h +++ b/movement/watch_faces/complication/simon_face.h @@ -71,12 +71,22 @@ typedef enum SimonPlayingState { SIMON_READY_FOR_NEXT_NOTE } SimonPlayingState; +typedef enum SimonMode { + SIMON_MODE_NORMAL = 0, // 5 Second timeout if nothing is input + SIMON_MODE_EASY, // There is no timeout in this mode + SIMON_MODE_HARD, // The speed of the teaching is doubled and th etimeout is halved + SIMON_MODE_TOTAL +} SimonMode; + typedef struct { uint8_t best_score; SimonNote sequence[MAX_SEQUENCE]; uint8_t sequence_length; uint8_t teaching_index; uint8_t listen_index; + bool soundOff; + bool lightOff; + uint8_t mode:6; SimonPlayingState playing_state; } simon_state_t; @@ -94,4 +104,8 @@ void simon_face_resign(movement_settings_t *settings, void *context); NULL, \ }) +#define TIMER_MAX 5 +#define SIMON_FACE_FREQUENCY 8 +#define DELAY_FOR_TONE_MS 300 + #endif // SIMON_FACE_H_