Make it count coins

This commit is contained in:
akasaka 2023-05-19 19:03:56 +09:00
parent 574a019cbb
commit 27b31c5ae6
7 changed files with 299 additions and 60 deletions

View File

@ -10,9 +10,10 @@
"includePath": [ "includePath": [
"d:/Code/wacca-vfd/firm/include", "d:/Code/wacca-vfd/firm/include",
"d:/Code/wacca-vfd/firm/src", "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/cores/arduino",
"C:/Users/akasaka/.platformio/packages/framework-arduino-avr/variants/sparkfun_promicro", "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/HID/src",
"C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SPI/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SPI/src",
"C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SoftwareSerial/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SoftwareSerial/src",
@ -24,9 +25,10 @@
"path": [ "path": [
"d:/Code/wacca-vfd/firm/include", "d:/Code/wacca-vfd/firm/include",
"d:/Code/wacca-vfd/firm/src", "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/cores/arduino",
"C:/Users/akasaka/.platformio/packages/framework-arduino-avr/variants/sparkfun_promicro", "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/HID/src",
"C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SPI/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SPI/src",
"C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SoftwareSerial/src", "C:/Users/akasaka/.platformio/packages/framework-arduino-avr/libraries/SoftwareSerial/src",

12
firm/include/coin.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef COIN_H_
#define COIN_H_
#include <stdint.h>
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

17
firm/include/settings.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef SETTINGS_H_
#define SETTINGS_H_
#include <stdint.h>
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

View File

@ -11,7 +11,9 @@
[env:sparkfun_promicro8] [env:sparkfun_promicro8]
platform = atmelavr platform = atmelavr
board = sparkfun_promicro8 board = sparkfun_promicro8
upload_port = COM25 upload_port = COM18
monitor_port = COM25 monitor_port = COM18
monitor_speed = 9600 monitor_speed = 9600
framework = arduino framework = arduino
lib_deps =
prosenb/EEPROMWearLevel@^2.1.0

76
firm/src/coin.cpp Normal file
View File

@ -0,0 +1,76 @@
#include <coin.h>
#include <settings.h>
#include <Arduino.h>
#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;
}

View File

@ -1,82 +1,184 @@
#include <Arduino.h> #include <Arduino.h>
#include <futaba.h> #include <futaba.h>
#include <rsrc.h> #include <rsrc.h>
#include <settings.h>
#include <coin.h>
extern "C" { extern "C" {
void setup(); void setup();
void loop(); 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() { void setup() {
cfg_begin();
coin_begin();
ftb_init(); ftb_init();
delay(1000);
ftb_reset(); ftb_reset();
ftb_power(true); ftb_power(true);
ftb_brightness(BRIGHT_25); ftb_brightness(BRIGHT_50);
ftb_canvas_shift(0); ftb_canvas_shift(0);
ftb_cursor(0, 0); ftb_cursor(0, 0);
ftb_font_size(FONT_16_16); 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) { typedef enum {
for(uint16_t x = from; x < to; x++) { LOGO_IN,
ftb_canvas_shift(x); LOGO_STAY,
delay(w); 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() { void loop() {
img_data_t tmp; unsigned long now_time = millis();
ftb_canvas_shift(0); if(now_time - last_millis > 1) {
tmp = img_invert(&IMG_WOCAO); last_millis = now_time;
ftb_draw_image(&IMG_WOCAO, 160, 0); if(task_coin()) {
scroll_from_to(0, 160, 10); now_phase = LOGO_IN;
delay(1000); logo_left = 0;
for(int i = 0; i < 4; i++) { coin_save_if_needed();
ftb_cursor(0, 0); return;
ftb_draw_image(&tmp, 160, 0); }
delay(250);
ftb_cursor(0, 0); task_idle();
ftb_draw_image(&IMG_WOCAO, 160, 0);
delay(250);
} }
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("");
} }

28
firm/src/settings.cpp Normal file
View File

@ -0,0 +1,28 @@
#include <settings.h>
#include <Arduino.h>
#include <EEPROMWearLevel.h>
#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;
}