#define DBG_ENABLE 0
#if DBG_ENABLE
#include <TinyDebug.h>
#endif
#define LED_FRAME_MS 5
#define LED_BLINK_INTERVAL_MS 300
typedef enum LED_STATUS
{
LED_STATUS_OFF,
LED_STATUS_ON,
LED_STATUS_BLINK,
};
typedef enum LED_SEQUENCE
{
LED_1 = 0,
LED_2,
LED_3,
LED_4,
LED_5,
LED_6,
LED_7,
LED_8,
LED_9,
LED_SEQ_TOTAL,
LED_SEQ_MIN = LED_1,
LED_SEQ_MAX = LED_9,
};
typedef enum LED_COLOR
{
LED_COLOR_A = 0,
LED_COLOR_B,
LED_COLOR_TOTAL,
LED_COLOR_MIN = LED_COLOR_A,
LED_COLOR_MAX = LED_COLOR_B
};
typedef enum LINE_SEQUENCE
{
LINE_1 = 0,
LINE_2 = 1,
LINE_3 = 2,
LINE_4 = 3,
LINE_5 = 4,
LINE_6 = 5,
LINE_7 = 6,
LINE_8 = 7,
LINE_SEQ_TOTAL,
};
typedef byte LED_P;
typedef byte LED_N;
typedef struct
{
LED_P P_pin;
LED_N N_pin;
} LED_T;
typedef struct
{
LED_STATUS status;
LED_T pin;
} SINGLE_LED_T;
class LED_SQUARE
{
public:
/**
* @brief construction
* @param *color_A_pin color A LED pin distribution
* @param *color_B_pin color B LED pin distribution
* @note pin distribution according to PCB layout
* @par sample code
* @code
* byte player_A_pin[] = {0,4,6,8,10,12,A0,A2,A4};
* byte player_B_pin[] = {1,5,7,9,11,13,A1,A3,A5};
* LED_SQUARE led_square(player_A_pin, player_B_pin);
*
* @endcode
*/
LED_SQUARE(LED_T *color_A_pin, LED_T *color_B_pin);
/**
* @brief destruction
*/
~LED_SQUARE();
/**
* @brief configure all the LED pin as output mode and set all off
*/
void begin(void);
/**
* @brief stop all LED behavior and reset variable
*/
void end(void);
/**
* @brief set status of specific LED
* @param LED_seq
* @param LED_color
* @param status
*/
void set_LEDStatus(LED_SEQUENCE LED_seq, LED_COLOR LED_color, LED_STATUS status);
/**
* @brief set all LED as OFF status
*/
void set_allOff(void);
/**
* @brief set all LED as ON status
*/
void set_allOn(void);
/**
* @brief set status of specific LED line
* @param Line_seq
* @param LED_color
* @param status
*/
void set_LineStatus(LINE_SEQUENCE Line_seq, LED_COLOR LED_color, LED_STATUS status);
/**
* @brief get status of specific LED
* @param LED_seq
* @param LED_color
* @return LED_STATUS
*/
LED_STATUS get_LEDStatus(LED_SEQUENCE LED_seq, LED_COLOR LED_color);
/**
* @brief find the sequence of next(sequence increase) idle LED(status OFF)
* @param LED_now current LED sequence
* @return result be founded, LED_SEQ_TOTAL means than result is invalid.
*/
LED_SEQUENCE find_IdleLed_Forward(LED_SEQUENCE LED_now);
/**
* @brief find the sequence of last(sequence decrease) idle LED(status OFF)
* @param LED_now current LED sequence
* @return result be founded, LED_SEQ_TOTAL means than result is invalid.
*/
LED_SEQUENCE find_IdleLed_Backword(LED_SEQUENCE LED_now);
/**
* @brief check all the LEDs in line match the specify condition
* @param LineSeq
* @param LED_color
* @param status
* @retval true LEDs in line match the specify condition
* @retval false LEDs in line not match the specify condition
*/
bool Is_LineBingo(LINE_SEQUENCE LineSeq, LED_COLOR LED_color, LED_STATUS status);
/**
* @brief count the number of line match the specify condition
* @param LED_color
* @param status
* @return the number of bingo line
*/
uint8_t get_LineBingo_number(LED_COLOR LED_color, LED_STATUS status);
/**
* @brief drive blink LED work, it needs to be execute in loop
* @par sample code
* @code
* loop
* {
* blinkRoutine();
* }
*
* @endcode
*/
void blinkRoutine(void);
/**
* @brief according to current status, calculate the next step
* @param LED_color color of now player
* @return next position
*/
LED_SEQUENCE BestNextMove(LED_COLOR LED_color);
/**
* @brief print LED distribution(for debug)
*/
void print_matrix(void);
private:
/**
* @brief configure all the LED pin as output mode
*/
void _allPin_OutputMode(void);
/**
* @brief control LED pin as ON or OFF
* @param pin_number
* @param status
* @arg HIGH
* @arg LOW
*/
void _controlLED(byte pin_P_number, byte pin_N_number, uint8_t status);
/**
* @brief find the sequence of next/last idle LED(status OFF)
* @param LED_now current LED sequence
* @param is_next
* @arg ture: next sequence
* @arg false: last sequence
* @return idle LED sequence, LED_SEQ_TOTAL means did not found
*/
LED_SEQUENCE _find_IdleLed(LED_SEQUENCE LED_now, bool is_next);
/**
* @brief count bit 1
* @param n
* @return total bit 1 in number
*/
uint8_t _minmax_popcount(uint32_t n);
/**
* @brief calculate minmax score
* @param MatrixMap_Friend
* @param MatrixMap_Enmy
* @return minmax score
*/
//int16_t _minmax_cal_score(T_MATRIX_3X3 MatrixMap_Friend, T_MATRIX_3X3 MatrixMap_Enmy);
/**
* @brief according to current friend and enmy status, calculate the next step
* @param MatrixMap_Friend map of friend
* @param MatrixMap_Enmy map of enmy
* @param WhoseTurn next step of friend or enmy
* @return next position
*/
//MATRIX_3X3_ELEMENT _BestNextMove_Wrapper(T_MATRIX_3X3 MatrixMap_Friend, T_MATRIX_3X3 MatrixMap_Enmy, PLAYER_TYPE WhoseTurn);
/**
* @brief according to current friend and enmy status, calculate the score
* @param MatrixMap_Friend map of friend
* @param MatrixMap_Enmy map of enmy
* @param alpha_score
* @param beta_score
* @param WhoseTurn
* @return score of current state in WhoseTurn
*/
//int16_t _minmax(T_MATRIX_3X3 MatrixMap_Friend, T_MATRIX_3X3 MatrixMap_Enmy, int16_t alpha_score, int16_t beta_score, PLAYER_TYPE WhoseTurn);
//void _print_matrix(T_MATRIX_3X3 MatrixMap_Friend, T_MATRIX_3X3 MatrixMap_Enmy);
//void _print_matrix_row(uint8_t friend_enable, uint8_t enmy_enable);
/** LED information */
//SINGLE_LED_T LED_data[LED_SEQ_TOTAL][LED_COLOR_TOTAL];
SINGLE_LED_T LED_data[LED_SEQ_TOTAL][LED_COLOR_TOTAL];
/** blinking LED status */
LED_STATUS LED_blink_status;
/** LED bitmap */
//T_MATRIX_3X3 MatrixBitmap[LED_COLOR_TOTAL];
/** blinking LED millis accumulation */
unsigned long LED_blink_millis_accumulation;
unsigned long LED_duration_start;
unsigned long LED_duration_end;
};
#define LED_PIN_0 PB0
#define LED_PIN_1 PB1
#define LED_PIN_2 PB2
#define LED_PIN_3 PB3
#define LED_PIN_4 PB4
LED_T LED[18] = {{PB0, PB1},
{PB0, PB2},
{PB0, PB3},
{PB0, PB4},
{PB1, PB0},
{PB1, PB2},
{PB1, PB3},
{PB1, PB4},
{PB2, PB0},
{PB2, PB1},
{PB2, PB3},
{PB2, PB4},
{PB3, PB0},
{PB3, PB1},
{PB3, PB2},
{PB3, PB4},
{PB4, PB0},
{PB4, PB1}};
LED_T player_A_pin[LED_SEQ_TOTAL] = {{PB0, PB1},
{PB1, PB0},
{PB2, PB0},
{PB0, PB3},
{PB1, PB3},
{PB2, PB3},
{PB3, PB0},
{PB3, PB2},
{PB4, PB0}};
LED_T player_B_pin[LED_SEQ_TOTAL] = {{PB0, PB2},
{PB1, PB2},
{PB2, PB1},
{PB0, PB4},
{PB1, PB4},
{PB2, PB4},
{PB3, PB1},
{PB3, PB4},
{PB4, PB1}};
LED_SQUARE::LED_SQUARE(LED_T *color_A_pin, LED_T *color_B_pin)
{
LED_blink_status = LED_STATUS_OFF;
LED_blink_millis_accumulation = 0;
SINGLE_LED_T *p_led = &LED_data[LED_1][LED_COLOR_A];
for (uint8_t i = 0; i < LED_SEQ_TOTAL; i++)
{
p_led->pin = color_A_pin[i];
p_led += LED_COLOR_TOTAL;
}
p_led = &LED_data[LED_1][LED_COLOR_B];
for (uint8_t i = 0; i < LED_SEQ_TOTAL; i++)
{
p_led->pin = color_B_pin[i];
p_led += LED_COLOR_TOTAL;
}
}
LED_SQUARE::~LED_SQUARE()
{
//end();
}
void LED_SQUARE::set_LEDStatus(LED_SEQUENCE LED_seq, LED_COLOR LED_color, LED_STATUS status)
{
SINGLE_LED_T *p_led = (SINGLE_LED_T *)&LED_data[LED_seq][LED_color];
p_led->status = status;
}
void LED_SQUARE::set_allOff(void)
{
for (uint8_t color = 0; color < LED_COLOR_TOTAL; color++)
{
for (uint8_t sequence = 0; sequence < LED_SEQ_TOTAL; sequence++)
{
set_LEDStatus(sequence, color , LED_STATUS_OFF);
}
}
}
//void LED_SQUARE::_controlLED(byte pin_number, uint8_t status)
void LED_SQUARE::_controlLED(byte pin_P_number, byte pin_N_number, uint8_t status)
{
pinMode(LED_PIN_0, INPUT);
pinMode(LED_PIN_1, INPUT);
pinMode(LED_PIN_2, INPUT);
pinMode(LED_PIN_3, INPUT);
pinMode(LED_PIN_4, INPUT);
if (status == LED_STATUS_ON)
{
pinMode(pin_P_number, OUTPUT);
pinMode(pin_N_number, OUTPUT);
digitalWrite(pin_P_number, HIGH);
digitalWrite(pin_N_number, LOW);
}
}
void LED_SQUARE::blinkRoutine(void)
{
unsigned long now = millis();
/*
Debug.print("now: ");
Debug.print(now, HEX);
Debug.print(", start: ");
Debug.print(LED_duration_start, HEX);
Debug.print(", end: ");
Debug.println(LED_duration_end, HEX);
*/
/* update blink parameter*/
if (now - LED_blink_millis_accumulation > LED_BLINK_INTERVAL_MS)
{
LED_blink_millis_accumulation = now;
LED_blink_status = (LED_blink_status == LED_STATUS_ON) ? LED_STATUS_OFF : LED_STATUS_ON;
}
/* update led HW*/
if (now >= LED_duration_start && now < LED_duration_end)
{
//100,
//102, 2/5 = 0.4
//107, 7/5 = 1.4
//109, 9/5 = 1.8
//110, 10/5 = 2
//114, 14/5 = 2.8
//100 + 5*18 = 190
//189 - 100 = 89
unsigned long diff = now - LED_duration_start;
byte index = 0;
index = diff / LED_FRAME_MS;
//SINGLE_LED_T *p_led = (SINGLE_LED_T *)&LED_data[sequence][color];
//SINGLE_LED_T *p_led = (SINGLE_LED_T *)&LED_data[index];
SINGLE_LED_T *p_led = ((SINGLE_LED_T *)LED_data) + index;
//Debug.print("index: ");
//Debug.print(index);
//Debug.print(", status: ");
//Debug.println(p_led->status);
LED_STATUS output_status;
output_status = p_led->status;
if (output_status == LED_STATUS_BLINK)
{
output_status = LED_blink_status;
}
_controlLED(p_led->pin.P_pin, p_led->pin.N_pin, output_status);
}
else if (now > LED_duration_end)
{
//Debug.println(F("blinkRoutine exceed"));
LED_duration_start = now;
LED_duration_end = now + LED_FRAME_MS * LED_SEQ_TOTAL * LED_COLOR_TOTAL;
}
else
{
//Debug.println(F("blinkRoutine else"));
}
}
/*
void LED_SQUARE::begin(void)
{
_allPin_OutputMode();
set_allOff();
}
void LED_SQUARE::end(void)
{
//set_allOff();
LED_blink_status = LOW;
LED_blink_millis_accumulation = 0;
}
*/
class SimpleQueue {
public:
/**
* @brief queue construction
* @param item_size each item size
* @param item_number how many item
*/
SimpleQueue(uint32_t item_size, uint32_t item_number);
/**
* @brief queue destruction
*/
~SimpleQueue();
/**
* @brief queue is full or not
* @retval true queue is full, push will fail
* @retval false queue is not full
*/
bool isFull(void);
/**
* @brief queue is empty or not
* @retval true queue is empty, pop will fail
* @retval false queue is not empty
*/
bool isEmpty(void);
/**
* @brief number of item existed in queue
* @return press action count
*/
int32_t available(void);
/**
* @brief push item into queue
* @param *pItem point of item
* @retval true push success
* @retval false push fail
*/
bool push(void *pItem);
/**
* @brief pop item from queue
* @param *pItem point of item
* @retval true pop success
* @retval false pop fail
*/
bool pop(void *pItem);
/**
* @brief peek the index 0 item in queue, but no pop
* @param *pItem point of item
* @retval true peek success
* @retval false peek fail
*/
bool peek(void *pItem);
/**
* @brief peek the specified index item in queue, but not pop
* @param *pItem point of item
* @param index index of item
* @retval true peek success
* @retval false peek fail
*/
bool peekIndex(void *pItem, int32_t index);
/**
* @brief reset the queue
*/
void flush();
private:
/** queue start address */
uint8_t *pQueue;
/** queue total size (ItemSize * ItemTotalNumber) */
int32_t QueueSize;
/** item size */
int32_t ItemSize;
/** item total number */
int32_t ItemTotalNumber;
/** item number in queue*/
int32_t ItemNumber;
/** index to be pushed of queue*/
int32_t ItemWriteIdx;
/** index to be popped of queue*/
int32_t ItemReadIdx;
};
SimpleQueue::SimpleQueue(uint32_t item_size, uint32_t item_number)
{
uint32_t malloc_size;
malloc_size = item_size * item_number;
pQueue = NULL;
if (malloc_size)
{
pQueue = (uint8_t *)malloc(item_size * item_number);
if (pQueue)
{
ItemSize = item_size;
ItemTotalNumber = item_number;
QueueSize = ItemSize * ItemTotalNumber;
flush();
}
}
}
SimpleQueue::~SimpleQueue()
{
if (pQueue)
{
free(pQueue);
pQueue = NULL;
}
}
bool SimpleQueue::isFull()
{
if (pQueue)
{
if (ItemNumber == ItemTotalNumber)
return true;
}
return false;
}
bool SimpleQueue::isEmpty()
{
if (pQueue)
{
if (ItemNumber == 0)
return true;
}
return false;
}
int32_t SimpleQueue::available()
{
if (pQueue)
{
return ItemNumber;
}
return 0;
}
bool SimpleQueue::push(void *pItem)
{
if (pQueue)
{
if (!isFull())
{
uint8_t *pQueue_Write;
pQueue_Write = pQueue + ItemSize * ItemWriteIdx;
memcpy((void *)pQueue_Write, pItem, ItemSize);
ItemWriteIdx = (++ItemWriteIdx == ItemTotalNumber) ? 0 : ItemWriteIdx;
ItemNumber++;
return true;
}
}
return false;
}
bool SimpleQueue::pop(void *pItem)
{
if (pQueue)
{
if (!isEmpty())
{
uint8_t *pQueue_Read;
pQueue_Read = pQueue + ItemSize * ItemReadIdx;
memcpy(pItem, (void *)pQueue_Read, ItemSize);
ItemReadIdx = (++ItemReadIdx == ItemTotalNumber) ? 0 : ItemReadIdx;
ItemNumber--;
return true;
}
}
return false;
}
bool SimpleQueue::peekIndex(void *pItem, int32_t index)
{
if (pQueue)
{
if (index < ItemNumber)
{
uint8_t *pQueue_Read;
int32_t next_read_index;
next_read_index = ((ItemReadIdx + index) >= ItemTotalNumber) ? (ItemReadIdx + index - ItemTotalNumber) : (ItemReadIdx + index);
pQueue_Read = pQueue + ItemSize * next_read_index;
memcpy(pItem, (void *)pQueue_Read, ItemSize);
return true;
}
}
return false;
}
bool SimpleQueue::peek(void *pItem)
{
return peekIndex(pItem, 0);
}
void SimpleQueue::flush(void)
{
ItemNumber = 0;
ItemWriteIdx = 0;
ItemReadIdx = 0;
}
#define EVENT_QUEUE_LEN 4
#define ENCODER_BUTTON_DEBUG 0
#define BUTTON_DEBOUNCE_MS 3
#define BUTTON_CLICK_INTERVAL_MS 400
class Button
{
public:
/*! state of buttone state machine */
typedef enum
{
BUTTON_STATE_IDLE, /*!< button ready to detect */
BUTTON_STATE_DEBOUNCE_PROCESS, /*!< button is debouncing */
BUTTON_STATE_CLICK_INTERVAL_PROCESS, /*!< button multi-click processing */
BUTTON_STATE_SUSPEND, /*!< button is not detecting */
BUTTON_STATE_TOTAL, /*!< button is not create or released */
} BUTTON_STATE;
/**
* @brief construction
* @param hw_ext_id
* Board Nano(Uno, Mini, other 328-based) external interrupts pin supported.
* @arg EXTERNAL_INTERRUPT_D2: INT0
* @arg EXTERNAL_INTERRUPT_D3: INT1
* @param multi_click_interval
*/
//Button(EXTERNAL_INTERRUPT_ID hw_ext_id, unsigned int multi_click_interval);
Button(byte hw_ext_id, unsigned int multi_click_interval);
/**
* @brief destruction
*/
~Button();
/**
* @brief button create
* @retval true Button create successfully.
* @retval false Button create unsuccessfully.
*/
bool begin(void);
/**
* @brief button release
* @retval true Button release successfully.
* @retval false Button release unsuccessfully.
*/
bool end(void);
/**
* @brief button start to detect the press action
* @retval true Button start to detect successfully.
* @retval false Button start to detect unsuccessfully.
*/
bool startDetect(void);
/**
* @brief button stop to detect the press action
* @retval true Button stop to detect successfully.
* @retval false Button stop to detect unsuccessfully.
*/
bool stopDetect(void);
/**
* @brief action of button be triggered
* @retval true There is button action existed, get the action by \a read function.
* @retval false There is no button action existed.
* @see read()
*/
bool available(void);
/**
* @brief read the count of press action
* @return press action count
* @see available()
*/
uint8_t read(void);
/**
* @brief enable debounce or not
* @param is_skip
* @arg true: disable debounce
* @arg flase: enable debounce
*/
void skipDebounce(bool is_skip);
/**
* @brief read the status of button pin
* @retval Ture button pin High level
* @retval False button pin Low level
*/
bool pinRead(void);
/** button state */
BUTTON_STATE button_state;
byte get_button_status(void);
void PressUpdateRoutine(void);
void TimeUpdateRoutine(void);
private:
/** pointer of button which is active */
static Button *active_button;
/** HW external interrupt ID be allocated by button */
//EXTERNAL_INTERRUPT_ID ext_id;
byte ext_id;
/** HW timer ID be allocated by button */
//TIMER_ID timer_id;
/** multi-click detect interval by user defined */
unsigned int multi_click_interval_ms;
/** button debounce execute or not */
bool no_debounce;
/** button state */
//BUTTON_STATE button_state;
/** button click count */
uint8_t button_click;
/** queue for storage of button event */
SimpleQueue event_queue;
unsigned long TimeStamp;
/**
* @brief entry point of button state machine
* @param state
* @retval true Switching the state is successful.
* @retval false Switching the state is unsuccessful.
*/
bool _button_state_enter(BUTTON_STATE state);
/**
* @brief read the status of pin
* @param pin
* @retval HIGH The pin is HIGH level.
* @retval LOW The pin is LOW level.
*/
bool _pinRead_HighLow(byte pin);
/**
* @brief timer callback function that button object registered
*/
static void button_timer_irq(void);
/**
* @brief handle button timer callback function
*/
void button_timer_irq_handle(void);
/**
* @brief external interrupt callback function that button object registered
*/
static void button_ext_irq(void);
/**
* @brief handle button external interrupt callback function
*/
void button_ext_irq_handle(void);
};
Button *Button::active_button = NULL;
//Button::Button(EXTERNAL_INTERRUPT_ID hw_ext_id, unsigned int multi_click_interval) : Timer_Manager(), External_Interrupt_Manager(), event_queue(sizeof(uint8_t), EVENT_QUEUE_LEN)
Button::Button(byte hw_ext_id, unsigned int multi_click_interval) : event_queue(sizeof(uint8_t), EVENT_QUEUE_LEN)
{
ext_id = hw_ext_id;
//timer_id = TIMER_ID_1;
multi_click_interval_ms = multi_click_interval;
no_debounce = false;
button_click = 0;
button_state = BUTTON_STATE_TOTAL;
}
Button::~Button()
{
end();
}
bool Button::begin(void)
{
if (active_button == NULL)
{
//if (Timer_Manager::begin(timer_id, BUTTON_DEBOUNCE_MS, button_timer_irq))
{
//if (External_Interrupt_Manager::begin(ext_id, FALLING, button_ext_irq))
{
active_button = this;
_button_state_enter(BUTTON_STATE_IDLE);
return true;
}
//Timer_Manager::end(timer_id);
}
}
return false;
}
bool Button::end(void)
{
if (active_button)
{
//Timer_Manager::end(timer_id);
//External_Interrupt_Manager::end(ext_id);
button_state = BUTTON_STATE_TOTAL;
active_button = NULL;
return true;
}
return false;
}
bool Button::stopDetect(void)
{
if (active_button)
{
return _button_state_enter(BUTTON_STATE_SUSPEND);
}
return false;
}
bool Button::startDetect(void)
{
if (active_button)
{
return _button_state_enter(BUTTON_STATE_IDLE);
}
return false;
}
bool Button::available(void)
{
if (event_queue.available())
{
return true;
}
return false;
}
uint8_t Button::read(void)
{
uint8_t output = 0;
event_queue.pop(&output);
return output;
}
void Button::skipDebounce(bool is_skip)
{
no_debounce = is_skip;
}
bool Button::pinRead(void)
{
//return _pinRead_HighLow(External_Interrupt_Manager::getPin(ext_id));
return _pinRead_HighLow(ext_id);
}
bool Button::_button_state_enter(BUTTON_STATE state)
{
int reason = 0;
if (state == BUTTON_STATE_DEBOUNCE_PROCESS && no_debounce)
{
reason = -1;
goto SKIP_BUTTON_STATE;
}
if (state == BUTTON_STATE_CLICK_INTERVAL_PROCESS && !multi_click_interval_ms)
{
reason = -2;
goto SKIP_BUTTON_STATE;
}
switch (state)
{
case BUTTON_STATE_IDLE:
{
button_click = 0;
//Timer_Manager::stop(timer_id);
//External_Interrupt_Manager::resume(ext_id);
}
break;
case BUTTON_STATE_DEBOUNCE_PROCESS:
{
// External_Interrupt_Manager::suspend(ext_id);
//Timer_Manager::restart(timer_id, (float)BUTTON_DEBOUNCE_MS);
TimeStamp = millis();
}
break;
case BUTTON_STATE_CLICK_INTERVAL_PROCESS:
{
//Timer_Manager::restart(timer_id, (float)multi_click_interval_ms);
//External_Interrupt_Manager::resume(ext_id);
TimeStamp = millis();
}
break;
case BUTTON_STATE_SUSPEND:
{
//External_Interrupt_Manager::suspend(ext_id);
//Timer_Manager::stop(timer_id);
}
break;
default:
{
reason = -3;
goto SKIP_BUTTON_STATE;
}
break;
}
button_state = state;
SKIP_BUTTON_STATE:
#if ENCODER_BUTTON_DEBUG
Tic_Tac_Toe_print("_button_state_enter: state = ");
Tic_Tac_Toe_print(state);
Tic_Tac_Toe_print(" reason = ");
Tic_Tac_Toe_println(reason);
#endif
//Debug.print("button state: "); Debug.println(button_state);
if (reason == 0)
{
return true;
}
return false;
}
bool Button::_pinRead_HighLow(byte pin)
{
if (pin >= 0 && pin <= 13)
{
return digitalRead(pin) == HIGH ? true : false;
}
if (pin >= A0 && pin <= A3)
{
return analogRead(pin) ? true : false;
}
return false;
}
void Button::button_timer_irq_handle(void)
{
//Timer_Manager::stop(timer_id);
#if DBG_ENABLE
Debug.print("button_timer_irq_handle: "); Debug.println(button_state);
#endif
if (button_state == BUTTON_STATE_DEBOUNCE_PROCESS)
{
//if (!_pinRead_HighLow(External_Interrupt_Manager::getPin(ext_id))) //low active, button press
if (!_pinRead_HighLow(ext_id)) //low active, button press
{
//valid button debounce
button_click++;
}
if (!_button_state_enter(BUTTON_STATE_CLICK_INTERVAL_PROCESS))
{
#if DBG_ENABLE
Debug.print("push 1137: "); Debug.println(button_click);
#endif
event_queue.push(&button_click);
_button_state_enter(BUTTON_STATE_IDLE);
}
}
else if (button_state == BUTTON_STATE_CLICK_INTERVAL_PROCESS)
{
button_click = 255;
#if DBG_ENABLE
Debug.print("push 1145: "); Debug.println(button_click);
#endif
event_queue.push(&button_click);
//_button_state_enter(BUTTON_STATE_IDLE);
_button_state_enter(BUTTON_STATE_SUSPEND);
}
else
{
#if ENCODER_BUTTON_DEBUG
Tic_Tac_Toe_print("!!! button_timer_irq_handle state wrong: ");
Tic_Tac_Toe_println(button_state);
#endif
}
}
void Button::button_ext_irq_handle(void)
{
//External_Interrupt_Manager::suspend(ext_id);
#if DBG_ENABLE
Debug.print("button_ext_irq_handle: "); Debug.println(button_state);
#endif
if (BUTTON_STATE_IDLE == button_state)
{
if (!_button_state_enter(BUTTON_STATE_DEBOUNCE_PROCESS))
{
button_click++;
if (!_button_state_enter(BUTTON_STATE_CLICK_INTERVAL_PROCESS))
{
#if DBG_ENABLE
Debug.print("push 1170: "); Debug.println(button_click);
#endif
event_queue.push(&button_click);
_button_state_enter(BUTTON_STATE_IDLE);
}
}
}
else if (BUTTON_STATE_CLICK_INTERVAL_PROCESS == button_state)
{
#if DBG_ENABLE
Debug.print("push 1177: "); Debug.println(button_click);
#endif
event_queue.push(&button_click);
_button_state_enter(BUTTON_STATE_IDLE);
}
else if (BUTTON_STATE_SUSPEND == button_state)
{
_button_state_enter(BUTTON_STATE_IDLE);
}
else
{
#if ENCODER_BUTTON_DEBUG
Tic_Tac_Toe_print("!!! button_ext_irq_handle state wrong: ");
Tic_Tac_Toe_println(button_state);
#endif
}
}
void Button::button_timer_irq(void)
{
if (active_button)
{
active_button-> button_timer_irq_handle();
}
}
void Button::button_ext_irq(void)
{
if (active_button)
{
active_button-> button_ext_irq_handle();
}
}
byte Button::get_button_status(void)
{
return (byte)button_state;
//if (active_button)
//{
//active_button-> button_state;
//}
}
void Button::PressUpdateRoutine(void)
{
if (BUTTON_STATE_IDLE == button_state)
{
if (pinRead() == LOW)
{
button_ext_irq();
}
}
else if (BUTTON_STATE_CLICK_INTERVAL_PROCESS == button_state)
{
if (pinRead() == HIGH)
{
button_ext_irq();
}
}
else if (BUTTON_STATE_SUSPEND == button_state)
{
if (pinRead() == HIGH)
{
button_ext_irq();
}
}
}
void Button::TimeUpdateRoutine(void)
{
if (BUTTON_STATE_DEBOUNCE_PROCESS == button_state &&
millis() - TimeStamp > BUTTON_DEBOUNCE_MS)
{
button_timer_irq();
}
else if (BUTTON_STATE_CLICK_INTERVAL_PROCESS == button_state &&
millis() - TimeStamp > multi_click_interval_ms)
{
button_timer_irq();
}
}
ISR(PCINT0_vect)
{
//Debug.println(F("ISR PCINT0"));
}
const LED_SQUARE led_square(player_A_pin, player_B_pin);
Button button(A0, 400);
void setup() {
#if DBG_ENABLE
Debug.begin();
Debug.println(F("Hello, TinyDebug!"));
#endif
pinMode(LED_PIN_0, INPUT_PULLUP);
pinMode(PB5, INPUT_PULLUP);
button.begin();
//sei();
//GIMSK |= (1 << PCIE);
//PCMSK |= (1 << PCINT5);
uint8_t i;
/*
for (i = 0; i < 18; i++)
{
pinMode(LED_PIN_0, INPUT);
pinMode(LED_PIN_1, INPUT);
pinMode(LED_PIN_2, INPUT);
pinMode(LED_PIN_3, INPUT);
pinMode(LED_PIN_4, INPUT);
pinMode(LED[i].P_pin, OUTPUT);
pinMode(LED[i].N_pin, OUTPUT);
digitalWrite(LED[i].P_pin, HIGH);
digitalWrite(LED[i].N_pin, LOW);
delay(100);
Debug.println(millis());
}
for (i = 0; i < 9; i++)
{
pinMode(LED_PIN_0, INPUT);
pinMode(LED_PIN_1, INPUT);
pinMode(LED_PIN_2, INPUT);
pinMode(LED_PIN_3, INPUT);
pinMode(LED_PIN_4, INPUT);
pinMode(player_A_pin[i].P_pin, OUTPUT);
pinMode(player_A_pin[i].N_pin, OUTPUT);
digitalWrite(player_A_pin[i].P_pin, HIGH);
digitalWrite(player_A_pin[i].N_pin, LOW);
delay(100);
Debug.println(millis());
}
for (i = 0; i < 9; i++)
{
pinMode(LED_PIN_0, INPUT);
pinMode(LED_PIN_1, INPUT);
pinMode(LED_PIN_2, INPUT);
pinMode(LED_PIN_3, INPUT);
pinMode(LED_PIN_4, INPUT);
pinMode(player_B_pin[i].P_pin, OUTPUT);
pinMode(player_B_pin[i].N_pin, OUTPUT);
digitalWrite(player_B_pin[i].P_pin, HIGH);
digitalWrite(player_B_pin[i].N_pin, LOW);
delay(100);
Debug.println(millis());
}
*/
led_square.set_allOff();
led_square.set_LEDStatus(LED_1, LED_COLOR_A, LED_STATUS_ON);
led_square.set_LEDStatus(LED_1, LED_COLOR_B, LED_STATUS_ON);
led_square.set_LEDStatus(LED_2, LED_COLOR_A, LED_STATUS_ON);
led_square.set_LEDStatus(LED_2, LED_COLOR_B, LED_STATUS_ON);
led_square.set_LEDStatus(LED_3, LED_COLOR_A, LED_STATUS_ON);
led_square.set_LEDStatus(LED_3, LED_COLOR_B, LED_STATUS_ON);
led_square.set_LEDStatus(LED_4, LED_COLOR_A, LED_STATUS_ON);
led_square.set_LEDStatus(LED_4, LED_COLOR_B, LED_STATUS_ON);
led_square.set_LEDStatus(LED_5, LED_COLOR_A, LED_STATUS_ON);
led_square.set_LEDStatus(LED_5, LED_COLOR_B, LED_STATUS_ON);
led_square.set_LEDStatus(LED_6, LED_COLOR_A, LED_STATUS_ON);
led_square.set_LEDStatus(LED_6, LED_COLOR_B, LED_STATUS_ON);
led_square.set_LEDStatus(LED_7, LED_COLOR_A, LED_STATUS_ON);
led_square.set_LEDStatus(LED_7, LED_COLOR_B, LED_STATUS_ON);
led_square.set_LEDStatus(LED_8, LED_COLOR_A, LED_STATUS_ON);
led_square.set_LEDStatus(LED_8, LED_COLOR_B, LED_STATUS_ON);
led_square.set_LEDStatus(LED_9, LED_COLOR_A, LED_STATUS_ON);
led_square.set_LEDStatus(LED_9, LED_COLOR_B, LED_STATUS_ON);
//led_square.set_LEDStatus(LED_5, LED_COLOR_A, LED_STATUS_BLINK);
//led_square.set_LEDStatus(LED_7, LED_COLOR_B, LED_STATUS_BLINK);
}
void loop() {
led_square.blinkRoutine();
//delay(500);
button.PressUpdateRoutine();
button.TimeUpdateRoutine();
//Debug.println(digitalRead(PB5));
//Debug.println(button.pinRead());
//Debug.println(button.get_button_status());
byte read_value = button.read();
if (read_value != 0)
{
#if DBG_ENABLE
Debug.print("button read: "); Debug.println(read_value);
#endif
}
}