mirror of
https://github.com/firewalkwithm3/Sensor-Watch.git
synced 2024-11-22 03:01:51 +08:00
Added Timeout; Ability to turn off LED and Sound; Added doublespeed mode. (#1)
* Check that color is valid Instead of merely checking that COLOR is set, check that it is one of RED, BLUE or GREEN * Added ability to turn off sound and timer with modes * Added enum for mode --------- Co-authored-by: Wesley Ellis <tahnok@gmail.com>
This commit is contained in:
parent
9794f86430
commit
3eaf807590
6
make.mk
6
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_
|
||||
|
|
Loading…
Reference in a new issue