/**** Includes ****/
#include "../utils/utils.h"
#include "button.h"

using namespace hw;

/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/

/**** Public function definitions ****/
hw::Button::Button(board::DigitalIn* din_ch, uint8_t act_lvl, uint8_t dbnc_lim, uint8_t init_state)
{
	this->din_ch = din_ch;
	
	if(act_lvl) this->act_lvl = board::DIN_HIGH;
	else this->act_lvl = board::DIN_LOW;
	
	this->dbnc_cnter = 0;
	this->dbnc_lim = dbnc_lim;
	
	if(init_state) this->state = BUTTON_ON;
	else this->state = BUTTON_OFF;
	
	this->time = 0;
	this->is_new = 0;
}

hw::Button::~Button(void)
{
	return;
}

uint8_t hw::Button::read(void)
{
	// Read din level
	uint8_t lvl = this->din_ch->read();
	
	// Increase state counter
	this->time = util::sat_add(this->time, 1);
	
	// Determine next state
	uint8_t next_state = BUTTON_OFF;
	if(lvl==this->act_lvl) next_state = BUTTON_ON;
	
	// Advance debounce sample counter
	if(next_state != this->state) this->dbnc_cnter++;
	else this->dbnc_cnter = 0;
	
	// Check for debounce end
	if(this->dbnc_cnter < this->dbnc_lim) return this->state;
	
	// Debounce end. Apply new state.
	this->state = next_state;
	this->time = 0;
	this->is_new = 1;
	this->dbnc_cnter = 0;
	
	return this->state;
}

uint8_t hw::Button::force_read(void)
{
	// Read din level
	uint8_t lvl = this->din_ch->read();
	
	// Cancels active debounce
	this->dbnc_cnter = 0;
	
	// Determine next state
	uint8_t next_state = BUTTON_OFF;
	if(lvl==this->act_lvl) next_state = BUTTON_ON;
	
	if(next_state != this->state)
	{
		this->state = next_state;
		this->time = 0;
		this->is_new = 1;
	};
	
	return this->state;
}

/**** Private function definitions ****/
