diff --git a/firm/.vscode/c_cpp_properties.json b/firm/.vscode/c_cpp_properties.json index add598a..9edd373 100644 --- a/firm/.vscode/c_cpp_properties.json +++ b/firm/.vscode/c_cpp_properties.json @@ -10,9 +10,10 @@ "includePath": [ "d:/Code/wacca-vfd/firm/include", "d:/Code/wacca-vfd/firm/src", + "d:/Code/wacca-vfd/firm/.pio/libdeps/sparkfun_promicro8/EEPROMWearLevel/src", + "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/EEPROM/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/cores/arduino", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/variants/sparkfun_promicro", - "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/EEPROM/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/HID/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SPI/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SoftwareSerial/src", @@ -24,9 +25,10 @@ "path": [ "d:/Code/wacca-vfd/firm/include", "d:/Code/wacca-vfd/firm/src", + "d:/Code/wacca-vfd/firm/.pio/libdeps/sparkfun_promicro8/EEPROMWearLevel/src", + "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/EEPROM/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/cores/arduino", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/variants/sparkfun_promicro", - "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/EEPROM/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/HID/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SPI/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SoftwareSerial/src", diff --git a/firm/include/coin.h b/firm/include/coin.h new file mode 100644 index 0000000..a0f725d --- /dev/null +++ b/firm/include/coin.h @@ -0,0 +1,12 @@ +#ifndef COIN_H_ +#define COIN_H_ +#include + +void coin_begin(); +void coin_set_callback(void (*fun_ptr)(uint32_t, uint32_t)); +void coin_save_if_needed(); +uint32_t coin_get(); +uint32_t coin_get_amt(); +bool coin_reset_if_needed(); + +#endif \ No newline at end of file diff --git a/firm/include/settings.h b/firm/include/settings.h new file mode 100644 index 0000000..f6e89dc --- /dev/null +++ b/firm/include/settings.h @@ -0,0 +1,17 @@ +#ifndef SETTINGS_H_ +#define SETTINGS_H_ +#include + +void cfg_begin(); + +typedef enum cfg_index { + CFG_READY = 0, + COIN_COUNT = 1, + MAX_INVALID +} cfg_index_t; + +bool cfg_valid(); +int32_t cfg_read(cfg_index_t); +void cfg_write(cfg_index_t, int32_t value); + +#endif \ No newline at end of file diff --git a/firm/platformio.ini b/firm/platformio.ini index fd0a8e1..e55dd50 100644 --- a/firm/platformio.ini +++ b/firm/platformio.ini @@ -11,7 +11,9 @@ [env:sparkfun_promicro8] platform = atmelavr board = sparkfun_promicro8 -upload_port = COM25 -monitor_port = COM25 +upload_port = COM18 +monitor_port = COM18 monitor_speed = 9600 -framework = arduino \ No newline at end of file +framework = arduino +lib_deps = + prosenb/EEPROMWearLevel@^2.1.0 diff --git a/firm/src/coin.cpp b/firm/src/coin.cpp new file mode 100644 index 0000000..0d20098 --- /dev/null +++ b/firm/src/coin.cpp @@ -0,0 +1,76 @@ +#include +#include +#include + +#define COIN_PIN 2 +#define COIN_DENOMINATION 100 + +static volatile int32_t coin_count_cache = 0; +static volatile bool coin_need_save = false; +static void (*callback)(uint32_t, uint32_t) = nullptr; + +void coin_call_callback() { + if(callback != nullptr && coin_count_cache > 0) { + callback(coin_count_cache, coin_count_cache * COIN_DENOMINATION); + } +} + +void coin_ISR() { + static unsigned long debounce_timer = 0; + unsigned long now_timer = millis(); + if(now_timer - debounce_timer > 200) { + coin_count_cache++; + coin_need_save = true; + coin_call_callback(); + debounce_timer = now_timer; + } +} + +void coin_begin() { + callback = nullptr; + pinMode(COIN_PIN, INPUT_PULLUP); + if(cfg_valid()) { + coin_count_cache = cfg_read(cfg_index::COIN_COUNT); + } +} + +bool coin_reset_if_needed() { + bool rslt = false; + if(digitalRead(COIN_PIN) == LOW) { + int millis_start = millis(); + while(digitalRead(COIN_PIN) == LOW) delay(1); + if(millis() - millis_start > 2000) { + cfg_write(cfg_index::COIN_COUNT, 0); + rslt = true; + } + } + + return rslt; +} + +bool haveInterrupt = false; +void coin_set_callback(void (*fun_ptr)(uint32_t, uint32_t)) { + if(!haveInterrupt) { + attachInterrupt(digitalPinToInterrupt(COIN_PIN), coin_ISR, LOW); + haveInterrupt = true; + } + callback = fun_ptr; +} + + +void coin_save_if_needed() { + if(coin_need_save) { + cli(); + cfg_write(cfg_index_t::COIN_COUNT, coin_count_cache); + coin_need_save = false; + sei(); + } +} + +uint32_t coin_get() { + return coin_count_cache; +} + +uint32_t coin_get_amt() { + return coin_get() * COIN_DENOMINATION; +} \ No newline at end of file diff --git a/firm/src/main.cpp b/firm/src/main.cpp index 7e390d1..94af583 100644 --- a/firm/src/main.cpp +++ b/firm/src/main.cpp @@ -1,82 +1,184 @@ #include #include #include +#include +#include extern "C" { void setup(); void loop(); } +volatile uint16_t time_coin_remain = 0; +volatile uint32_t coin_amount = 0; +uint32_t coin_disp_amount = 0; +volatile uint16_t coin_combo = 0; + +void coin_callback(uint32_t count, uint32_t amount) { + time_coin_remain = 5000; + coin_combo++; + coin_amount = amount; +} + +bool task_coin() { + if(time_coin_remain == 0) return false; + + time_coin_remain--; + + if(coin_disp_amount != coin_amount) { + ftb_canvas_shift(0); + char buf[21] = { 0 }; + ftb_cursor(0, 0); + if(coin_combo < 2) { + ftb_write("** SAVE SOME CASH **"); + } else { + ftb_write("** "); + sprintf(buf, "%u COMBO", coin_combo); + ftb_write(buf); + ftb_write(" **"); + memset(buf, 0, 21); + } + ftb_cursor(0, 2); + sprintf(buf, "TOTAL: %lu \\", coin_amount); + ftb_write(buf); + coin_disp_amount = coin_amount; + } + + if(time_coin_remain == 0) { + coin_combo = 0; + ftb_cursor(0, 0); + ftb_write(" "); + ftb_cursor(0, 2); + ftb_write(" "); + } + + return true; +} void setup() { + cfg_begin(); + coin_begin(); ftb_init(); - delay(1000); - ftb_reset(); ftb_power(true); - ftb_brightness(BRIGHT_25); + ftb_brightness(BRIGHT_50); ftb_canvas_shift(0); ftb_cursor(0, 0); ftb_font_size(FONT_16_16); + + bool coin_did_reset = coin_reset_if_needed(); + if(coin_did_reset) { + ftb_cursor(0, 0); + ftb_write("** COIN COUNT CLR **"); + delay(2000); + ftb_cursor(0, 0); + ftb_write(" "); + } + + coin_set_callback(coin_callback); } -void scroll_from_to(uint16_t from, uint16_t to, uint16_t w) { - for(uint16_t x = from; x < to; x++) { - ftb_canvas_shift(x); - delay(w); +typedef enum { + LOGO_IN, + LOGO_STAY, + LOGO_OUT, + TANOC_IN, + TANOC_STAY, + TANOC_OUT, + AMT_IN, + AMT_STAY, + AMT_OUT, +} idle_phase; + +idle_phase now_phase = LOGO_IN; +uint32_t logo_left = 0; +uint32_t logo_time = 0; + +void task_idle() { + switch(now_phase) { + case LOGO_IN: + case TANOC_IN: + if(logo_left == 0) { + ftb_cursor(0, 0); + ftb_draw_image(now_phase == LOGO_IN ? &IMG_WOCAO : &IMG_TANOC, 160, 0); + } else { + ftb_canvas_shift(logo_left); + } + logo_left++; + if(logo_left == 161) { + now_phase = (now_phase == LOGO_IN ? LOGO_STAY : TANOC_STAY); + logo_time = 1000; + } + break; + + case AMT_IN: + if(logo_left == 0) { + char buf1[21] = {0}; + char buf2[21] = {0}; + sprintf(buf1, "%lu coins", coin_get()); + sprintf(buf2, "Total: %lu \\", coin_get_amt()); + ftb_cursor(160, 0); + ftb_write(" "); + ftb_cursor(160, 0); + ftb_write(buf1); + ftb_cursor(160, 2); + ftb_write(" "); + ftb_cursor(160, 2); + ftb_write(buf2); + } else { + ftb_canvas_shift(logo_left); + } + logo_left++; + if(logo_left == 161) { + now_phase = AMT_STAY; + logo_time = 1000; + } + break; + + case LOGO_STAY: + case TANOC_STAY: + case AMT_STAY: + logo_time--; + if(logo_time == 0) { + switch(now_phase) { + case LOGO_STAY: now_phase = LOGO_OUT; break; + case TANOC_STAY: now_phase = TANOC_OUT; break; + case AMT_STAY: now_phase = AMT_OUT; break; + } + } + break; + + case LOGO_OUT: + case TANOC_OUT: + case AMT_OUT: + ftb_canvas_shift(logo_left); + logo_left++; + if(logo_left == 160*2 + 1) { + switch(now_phase) { + case LOGO_OUT: now_phase = TANOC_IN; break; + case TANOC_OUT: now_phase = AMT_IN; break; + case AMT_OUT: now_phase = LOGO_IN; break; + } + logo_left = 0; + } + break; } } +unsigned long last_millis = 0; void loop() { - img_data_t tmp; - ftb_canvas_shift(0); - tmp = img_invert(&IMG_WOCAO); - ftb_draw_image(&IMG_WOCAO, 160, 0); - scroll_from_to(0, 160, 10); - delay(1000); - for(int i = 0; i < 4; i++) { - ftb_cursor(0, 0); - ftb_draw_image(&tmp, 160, 0); - delay(250); - ftb_cursor(0, 0); - ftb_draw_image(&IMG_WOCAO, 160, 0); - delay(250); + unsigned long now_time = millis(); + if(now_time - last_millis > 1) { + last_millis = now_time; + if(task_coin()) { + now_phase = LOGO_IN; + logo_left = 0; + coin_save_if_needed(); + return; + } + + task_idle(); } - scroll_from_to(160, 160 * 2, 10); - - ftb_cursor(160 * 3, 0); - ftb_write(" "); - - ftb_canvas_shift(0); - tmp = img_invert(&IMG_TANOC); - ftb_cursor(0, 0); - - ftb_draw_image(&IMG_TANOC, 160, 0); - scroll_from_to(0, 160, 10); - delay(1000); - for(int i = 0; i < 4; i++) { - ftb_cursor(0, 0); - ftb_draw_image(&tmp, 160, 0); - delay(250); - ftb_cursor(0, 0); - ftb_draw_image(&IMG_TANOC, 160, 0); - delay(250); - } - scroll_from_to(160, 160 * 2, 10); - - ftb_cursor(160 * 3, 0); - ftb_write("** ALL SAS OELUTZ **"); - - scroll_from_to(160*2, 160 * 3, 10); - - ftb_scroll_box_make(0, 2, 160, 2); - ftb_scroll_speed(2); - ftb_scroll_text("Are you ready to RAVE to the music of HARDCORE TANO-C?? ENJOY the SUPER COOL mega Game WACCA, sunovabitch!! "); - ftb_scroll_start(); - - delay(10000); - - ftb_scroll_text(""); } diff --git a/firm/src/settings.cpp b/firm/src/settings.cpp new file mode 100644 index 0000000..90692a2 --- /dev/null +++ b/firm/src/settings.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#define SETTINGS_VERSION 0 +#define SETTINGS_MAGIC 0x3939 + +void cfg_begin() { + EEPROMwl.begin(SETTINGS_VERSION, cfg_index::MAX_INVALID); + if(!cfg_valid()) { + cfg_write(cfg_index::COIN_COUNT, 0); + cfg_write(cfg_index::CFG_READY, SETTINGS_MAGIC); + } +} + +int32_t cfg_read(cfg_index_t idx) { + int32_t tmp = -1; + EEPROMwl.get(idx, tmp); + return tmp; +} + +void cfg_write(cfg_index_t idx, int32_t value) { + EEPROMwl.put(idx, value); +} + +bool cfg_valid() { + return cfg_read(cfg_index::CFG_READY) == SETTINGS_MAGIC; +} \ No newline at end of file