Complete the countdown state machine
This commit is contained in:
parent
7d36e71923
commit
0de66a4f7b
|
@ -5,6 +5,10 @@ A: 11101110 0111 0111 0x77
|
||||||
M: 11101100 0111 0110 0x76
|
M: 11101100 0111 0110 0x76
|
||||||
O: 11111100 0111 1110 0x7E
|
O: 11111100 0111 1110 0x7E
|
||||||
F: 10001110 0001 0111 0x47
|
F: 10001110 0001 0111 0x47
|
||||||
|
#: 01101100 0110 0110 0x66 note: two vertical lines only
|
||||||
|
|: 00001100 0000 0110 0x06
|
||||||
|
d: 01111010 0110 1101 0x6D
|
||||||
|
H: 01101110 0110 0111 0x67
|
||||||
|
|
||||||
0: 11111100 0111 1110 0x7E
|
0: 11111100 0111 1110 0x7E
|
||||||
1: 01100000 0110 0000 0x60
|
1: 01100000 0110 0000 0x60
|
||||||
|
|
187
src/main.c
187
src/main.c
|
@ -11,10 +11,16 @@
|
||||||
typedef enum {
|
typedef enum {
|
||||||
COUNTDOWN_UNINITIALIZED,
|
COUNTDOWN_UNINITIALIZED,
|
||||||
COUNTDOWN_STOPPED,
|
COUNTDOWN_STOPPED,
|
||||||
|
COUNTDOWN_STOPPING,
|
||||||
COUNTDOWN_STARTING,
|
COUNTDOWN_STARTING,
|
||||||
COUNTDOWN_RUNNING
|
COUNTDOWN_RUNNING
|
||||||
} countdown_state_t;
|
} countdown_state_t;
|
||||||
|
|
||||||
|
static const uint32_t ONE_DAY = 86400 * 1000;
|
||||||
|
static const uint32_t ONE_HOUR = 3600 * 1000;
|
||||||
|
static const uint32_t ONE_MINUTE = 60 * 1000;
|
||||||
|
static const uint32_t ONE_SECOND = 1000;
|
||||||
|
|
||||||
static countdown_state_t m_countdown_state;
|
static countdown_state_t m_countdown_state;
|
||||||
static uint32_t m_last_state_change_time;
|
static uint32_t m_last_state_change_time;
|
||||||
|
|
||||||
|
@ -53,6 +59,53 @@ static void configure_ms_trig_alarm(void)
|
||||||
m_next_ms_trigger = timer_hw->timelr + 10000;
|
m_next_ms_trigger = timer_hw->timelr + 10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void show_time(uint32_t time_ms)
|
||||||
|
{
|
||||||
|
bool blinking_dot_on = (time_ms % 1000) < 500;
|
||||||
|
|
||||||
|
if(time_ms >= 100 * ONE_DAY) { // more than 100 days
|
||||||
|
// time too large to display
|
||||||
|
sseg_set_char(0, 'i', false);
|
||||||
|
sseg_set_char(1, 'n', false);
|
||||||
|
sseg_set_char(2, 'f', false);
|
||||||
|
} else if(time_ms >= 10 * ONE_DAY) { // 10 .. 100 days
|
||||||
|
// show days without decimal
|
||||||
|
uint32_t days = (time_ms + ONE_DAY/2) / ONE_DAY;
|
||||||
|
|
||||||
|
sseg_set_char(0, '0' + days / 10, false);
|
||||||
|
sseg_set_char(1, '0' + days % 10, blinking_dot_on);
|
||||||
|
sseg_set_char(2, 'd', false);
|
||||||
|
} else if(time_ms >= 10 * ONE_HOUR) { // 10 hours .. 10 days
|
||||||
|
// show days with one decimal
|
||||||
|
uint32_t decidays = (time_ms + ONE_DAY/20) * 10 / ONE_DAY;
|
||||||
|
|
||||||
|
sseg_set_char(0, '0' + decidays / 10, blinking_dot_on);
|
||||||
|
sseg_set_char(1, '0' + decidays % 10, false);
|
||||||
|
sseg_set_char(2, 'd', false);
|
||||||
|
} else if(time_ms >= 1000 * ONE_SECOND) { // 1000 seconds (0.27 hours) .. 10 hours
|
||||||
|
// show hours with one decimal
|
||||||
|
uint32_t decihours = (time_ms + ONE_HOUR/20) * 10 / ONE_HOUR;
|
||||||
|
|
||||||
|
sseg_set_char(0, '0' + decihours / 10, blinking_dot_on);
|
||||||
|
sseg_set_char(1, '0' + decihours % 10, false);
|
||||||
|
sseg_set_char(2, 'H', false);
|
||||||
|
} else if(time_ms >= 100 * ONE_SECOND) { // 100 .. 1000 seconds
|
||||||
|
// show seconds
|
||||||
|
uint32_t seconds = (time_ms + ONE_SECOND/2) / ONE_SECOND;
|
||||||
|
|
||||||
|
sseg_set_char(0, '0' + seconds / 100, false);
|
||||||
|
sseg_set_char(1, '0' + (seconds / 10) % 10, false);
|
||||||
|
sseg_set_char(2, '0' + seconds % 10, true);
|
||||||
|
} else { // <100 seconds
|
||||||
|
// show seconds with one decimal
|
||||||
|
uint32_t deciseconds = time_ms * 10 / ONE_SECOND;
|
||||||
|
|
||||||
|
sseg_set_char(0, '0' + deciseconds / 100, false);
|
||||||
|
sseg_set_char(1, '0' + (deciseconds / 10) % 10, true);
|
||||||
|
sseg_set_char(2, '0' + deciseconds % 10, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void update_countdown_fsm(uint32_t time_ms)
|
static void update_countdown_fsm(uint32_t time_ms)
|
||||||
{
|
{
|
||||||
countdown_state_t last_state = m_countdown_state;
|
countdown_state_t last_state = m_countdown_state;
|
||||||
|
@ -70,6 +123,9 @@ static void update_countdown_fsm(uint32_t time_ms)
|
||||||
|
|
||||||
case COUNTDOWN_STOPPED:
|
case COUNTDOWN_STOPPED:
|
||||||
if(state_entered) {
|
if(state_entered) {
|
||||||
|
// countdown has been stopped -> switch off the load
|
||||||
|
gpio_put(OUTPUT_ENABLE_PIN, true);
|
||||||
|
|
||||||
sseg_set_char(0, 'o', false);
|
sseg_set_char(0, 'o', false);
|
||||||
sseg_set_char(1, 'f', false);
|
sseg_set_char(1, 'f', false);
|
||||||
sseg_set_char(2, 'f', false);
|
sseg_set_char(2, 'f', false);
|
||||||
|
@ -81,16 +137,62 @@ static void update_countdown_fsm(uint32_t time_ms)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COUNTDOWN_STARTING:
|
case COUNTDOWN_STARTING:
|
||||||
// TODO: show a fancy animation + beep code
|
|
||||||
|
|
||||||
if(buttons_get_events(BTN_ON) & BTN_EVENT_RELEASED) {
|
if(buttons_get_events(BTN_ON) & BTN_EVENT_RELEASED) {
|
||||||
// button released too early -> back to stopped state
|
// button released too early -> back to stopped state
|
||||||
m_countdown_state = COUNTDOWN_STOPPED;
|
m_countdown_state = COUNTDOWN_STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(time_in_state == 3000) {
|
switch(time_in_state) {
|
||||||
m_countdown_off_time = time_ms + 30 * 60 * 1000;
|
case 1:
|
||||||
m_countdown_state = COUNTDOWN_RUNNING;
|
sseg_set_char(0, '|', false);
|
||||||
|
sseg_set_char(1, ' ', false);
|
||||||
|
sseg_set_char(2, ' ', false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 500:
|
||||||
|
sseg_set_char(0, '#', false);
|
||||||
|
buzzer_on(1000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1000:
|
||||||
|
sseg_set_char(1, '|', false);
|
||||||
|
buzzer_on(1414);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1500:
|
||||||
|
sseg_set_char(1, '#', false);
|
||||||
|
buzzer_on(2000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2000:
|
||||||
|
sseg_set_char(2, '|', false);
|
||||||
|
buzzer_on(2828);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2500:
|
||||||
|
sseg_set_char(2, '#', false);
|
||||||
|
buzzer_on(4000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 700:
|
||||||
|
case 1200:
|
||||||
|
case 1700:
|
||||||
|
case 2200:
|
||||||
|
case 2700:
|
||||||
|
buzzer_off();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3000:
|
||||||
|
if(buttons_is_pressed(BTN_OFF)) {
|
||||||
|
// „permanent on mode“
|
||||||
|
m_countdown_off_time = time_ms + 14 * ONE_DAY;
|
||||||
|
} else {
|
||||||
|
// default mode
|
||||||
|
m_countdown_off_time = time_ms + 30 * ONE_MINUTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_countdown_state = COUNTDOWN_RUNNING;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -102,9 +204,19 @@ static void update_countdown_fsm(uint32_t time_ms)
|
||||||
|
|
||||||
countdown_time_remaining = m_countdown_off_time - time_ms;
|
countdown_time_remaining = m_countdown_off_time - time_ms;
|
||||||
|
|
||||||
// TODO: show time on display
|
show_time(countdown_time_remaining);
|
||||||
// TODO: off button handling
|
|
||||||
// TODO: on button handling (extend time)
|
// off button pressed -> go to stop procedure
|
||||||
|
if(buttons_get_events(BTN_ON) & BTN_EVENT_PRESSED) {
|
||||||
|
m_countdown_state = COUNTDOWN_STOPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extend time when on button is pressed again
|
||||||
|
if(buttons_get_events(BTN_ON) & BTN_EVENT_PRESSED) {
|
||||||
|
if(countdown_time_remaining < 10 * ONE_HOUR) {
|
||||||
|
m_countdown_off_time += 30 * ONE_MINUTE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// beep codes
|
// beep codes
|
||||||
switch(countdown_time_remaining) {
|
switch(countdown_time_remaining) {
|
||||||
|
@ -142,6 +254,65 @@ static void update_countdown_fsm(uint32_t time_ms)
|
||||||
gpio_put(OUTPUT_ENABLE_PIN, false);
|
gpio_put(OUTPUT_ENABLE_PIN, false);
|
||||||
m_countdown_state = COUNTDOWN_STOPPED;
|
m_countdown_state = COUNTDOWN_STOPPED;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COUNTDOWN_STOPPING:
|
||||||
|
if(state_entered) {
|
||||||
|
buzzer_off();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(buttons_get_events(BTN_OFF) & BTN_EVENT_RELEASED) {
|
||||||
|
// button released too early -> back to running state
|
||||||
|
m_countdown_state = COUNTDOWN_RUNNING;
|
||||||
|
// add the time that the button was pressed to the deadline
|
||||||
|
m_countdown_off_time += time_in_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(time_in_state) {
|
||||||
|
case 1:
|
||||||
|
sseg_set_char(0, '#', false);
|
||||||
|
sseg_set_char(1, '#', false);
|
||||||
|
sseg_set_char(2, '#', false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 500:
|
||||||
|
sseg_set_char(0, '|', false);
|
||||||
|
buzzer_on(4000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1000:
|
||||||
|
sseg_set_char(0, ' ', false);
|
||||||
|
buzzer_on(2828);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1500:
|
||||||
|
sseg_set_char(1, '|', false);
|
||||||
|
buzzer_on(2000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2000:
|
||||||
|
sseg_set_char(1, ' ', false);
|
||||||
|
buzzer_on(1414);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2500:
|
||||||
|
sseg_set_char(2, '|', false);
|
||||||
|
buzzer_on(1000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 700:
|
||||||
|
case 1200:
|
||||||
|
case 1700:
|
||||||
|
case 2200:
|
||||||
|
case 2700:
|
||||||
|
buzzer_off();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3000:
|
||||||
|
m_countdown_state = COUNTDOWN_STOPPED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_countdown_state != last_state) {
|
if(m_countdown_state != last_state) {
|
||||||
|
|
19
src/sseg.c
19
src/sseg.c
|
@ -83,6 +83,25 @@ static uint8_t ascii_to_sseg(char c)
|
||||||
case 'F':
|
case 'F':
|
||||||
return 0x47;
|
return 0x47;
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
return 0x66;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
case 'I':
|
||||||
|
case '|':
|
||||||
|
return 0x06;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
return 0x6D;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
case 'H':
|
||||||
|
return 0x67;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
return 0x00;
|
||||||
|
|
||||||
default: // '-'
|
default: // '-'
|
||||||
return 0x01;
|
return 0x01;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue