/* ----------------------------------- Inclusões ----------------------------------- */
#include "button_interface.h"
#include "timer.h"
#include "led_matrix.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "motor.h"
/* ----------------------------------- Configurações ----------------------------------- */
#include "config.h"
/* ----------------------------------- Variaveis e Classes ----------------------------------- */
using namespace driver;
/* NOTEIRO */
constexpr uint32_t notes_pin = 19;
int notas_inserted = 0;
unsigned long read_control_notes = 0;
/* MOEDEIRO */
constexpr uint32_t coins_pin = 18;
/* --- LCD --- */
constexpr int LCD_ADDR = 0x27;
constexpr int LCD_COLUMNS = 20;
constexpr int LCD_ROWS = 4;
LiquidCrystal_I2C lcd(LCD_ADDR, LCD_COLUMNS, LCD_ROWS);
/* --- Botões --- */
constexpr btn_interface_t::pins_t BTN_PINS = { A2, A4, A3, A5, A6 };
btn_interface_t buttons(BTN_PINS);
/* --- Leds --- */
constexpr uint8_t LEDS_ROW_PINS[8] = { 8, 9, 10, 11, 12, 13, A0, A1 };
constexpr uint8_t LEDS_COLS_PINS[5] = { 2, 3, 4, 5, 6 };
led_matrix_t leds(LEDS_ROW_PINS, LEDS_COLS_PINS);
led_matrix_t::led_state_t led_state = { 0 };
/* --- Motores --- */
motor_t motores;
/* --- Sistema --- */
typedef enum {
state_idle = 0,
state_select_product,
state_moving_motor,
state_verify_money
} states_e;
states_e m_state = state_idle;
states_e m_last_state = m_state;
constexpr int PRESENCE_SENSOR_PIN = A7;
int total_money = 0;
int flag_disp = 0;
/* ----------------------------------- Funções ----------------------------------- */
int get_pin_num();
void process_button_act (btn_interface_t::btn_action_t btn_act);
bool get_presence_sensor();
bool verify_money_enough();
void update_display_insert_money();
void update_display_total_money ();
void update_dislay_selecione();
void update_display_dispensando();
void update_display_delivered();
void read_noteiro();
void read_moedeiro();
/* ----------------------------------- Rotinas ----------------------------------- */
void setup() {
pinMode(PRESENCE_SENSOR_PIN, INPUT_PULLUP);
pinMode(notes_pin, INPUT);
pinMode(coins_pin, INPUT);
pinMode(LED_BUILTIN, OUTPUT);
lcd.init();
lcd.backlight();
lcd.clear();
update_display_insert_money();
update_display_total_money();
attachInterrupt(digitalPinToInterrupt(notes_pin), read_noteiro, RISING);
attachInterrupt(digitalPinToInterrupt(coins_pin), read_moedeiro, RISING);
}
void loop() {
timer_t tim(tempo_colunas_s[led_state.col], millis()); // verifica qual coluna estamos para dar esse tempo
static timer_t tim_reset(TEMPO_DE_RESET, millis());
if (m_last_state != m_state){
tim_reset.reset_timer();
} else if (tim_reset.timer_count_zero()) {
total_money = 0;
m_state = state_idle;
m_last_state = m_state;
flag_disp = 0;
update_display_insert_money();
update_display_total_money();
tim_reset.reset_timer();
}
switch (m_state) {
case state_idle:
{
leds.clear();
led_state.row = 0;
led_state.col = 0;
if(((millis() - read_control_notes) > TEMPO_LEITURA_NOTAS_MOEDAS) && (notas_inserted > 0) ){
tim_reset.reset_timer();
total_money = total_money + notas_inserted;
notas_inserted = 0;
update_display_total_money();
if (verify_money_enough()) {
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(2, 0);
lcd.print("Clique em Enter");
lcd.setCursor(2, 1);
lcd.print("ou insira mais");
flag_disp++;
}
}
if (flag_disp > 0) {
process_button_act(buttons.get_action());
}
leds.clear();
break;
}
case state_select_product:
{
lcd.setCursor(2, 1);
lcd.print(" ");
if (flag_disp == 0) {
flag_disp++;
update_dislay_selecione();
}
process_button_act(buttons.get_action());
break;
}
case state_moving_motor:
{
update_display_dispensando();
bool scape = false;
bool delivered = false;
while (!tim.timer_count_zero() && scape == false) {
tim_reset.reset_timer();
if(!get_presence_sensor()) {
scape = true;
delivered = true;
break;
}
delivered = false;
bool flag = false;
if (flag == false) {
flag = true;
motores.set_level(get_pin_num(), true);
}
delay(50);
}
motores.set_level(get_pin_num(), false);
flag_disp = 0;
if (delivered) {
update_display_delivered();
delay(2000);
m_state = state_verify_money;
} else {
m_state = state_select_product;
}
delay(500);
break;
}
case state_verify_money:
{
total_money = total_money - custo_coluns_rs[led_state.col];
update_display_total_money();
update_display_insert_money();
m_state = state_idle;
flag_disp = 0;
break;
}
default:
{
break;
}
}
m_last_state = m_state;
}
void process_button_act(btn_interface_t::btn_action_t btn_act) {
if (btn_act != btn_interface_t::btn_action_t::NONE && btn_act != btn_interface_t::btn_action_t::CENTER) {
led_state.state = false;
leds.set_led(led_state);
}
switch (btn_act) {
case btn_interface_t::btn_action_t::LEFT:
{
if (led_state.col == 4) {
led_state.col = 0;
} else {
led_state.col++;
}
break;
}
case btn_interface_t::btn_action_t::RIGHT:
{
if (led_state.col == 0) {
led_state.col = 4;
} else {
led_state.col--;
}
break;
}
case btn_interface_t::btn_action_t::TOP:
{
if (led_state.row == 0) {
led_state.row = 7;
} else {
led_state.row--;
}
break;
}
case btn_interface_t::btn_action_t::DOWN:
{
if (led_state.row == 7) {
led_state.row = 0;
} else {
led_state.row++;
}
break;
}
case btn_interface_t::btn_action_t::CENTER:
{
if (m_state == state_idle) {
if (verify_money_enough()) {
m_state = state_select_product;
flag_disp = 0;
} else {
update_display_insert_money();
}
} else if (m_state == state_select_product) {
int delta = total_money - custo_coluns_rs[led_state.col];
if (delta >= 0) {
m_state = state_moving_motor;
flag_disp = 0;
}
}
break;
}
case btn_interface_t::btn_action_t::NONE:
{
break;
}
}
led_state.state = true;
leds.set_led(led_state);
}
bool get_presence_sensor() {
return digitalRead(PRESENCE_SENSOR_PIN);
}
void update_display_total_money() {
char buffer[8];
sprintf(buffer, "%02d,00", total_money);
lcd.setCursor(4, 3);
lcd.print(buffer);
lcd.setCursor(10, 3);
lcd.print("Reais");
}
void update_dislay_selecione() {
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print("Selecione o Produto");
}
int get_pin_num() {
int ret_val = 0;
int row = led_state.row;
int col = led_state.col;
if (row >= 0 && row < 8 && col >= 0 && col < 5) {
ret_val = (row * 5) + col;
} else {
ret_val = -1;
}
return ret_val;
}
void read_noteiro() {
notas_inserted++;
read_control_notes = millis();
}
void read_moedeiro() {
notas_inserted++;
read_control_notes = millis();
}
bool verify_money_enough() {
int cheaper_product = 1000000;
for (int i = 0; i < 5; i++) {
if (cheaper_product > custo_coluns_rs[i]){
cheaper_product = custo_coluns_rs[i];
}
}
return total_money >= cheaper_product;
}
void update_display_insert_money() {
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(1, 0);
lcd.print("Insira o Dinheiro");
}
void update_display_dispensando() {
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print("Dispensando Produto");
}
void update_display_delivered() {
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(4, 0);
lcd.print("Entregue!");
}
/*
- Lógica Moedeiro e Noteiro.
- Lógica para gerenciar dinheiro que temos.
*/