/**
 *
 * \file
 *
 * \brief This module contains SAMD21 BSP APIs implementation.
 *
 * Copyright (c) 2017-2018 Microchip Technology Inc. and its subsidiaries.
 *
 * \asf_license_start
 *
 * \page License
 *
 * Subject to your compliance with these terms, you may use Microchip
 * software and any derivatives exclusively with Microchip products.
 * It is your responsibility to comply with third party license terms applicable
 * to your use of third party software (including open source software) that
 * may accompany Microchip software.
 *
 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
 * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
 * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
 * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
 * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
 * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
 * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
 * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
 * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
 *
 * \asf_license_stop
 *
 */
 
#include "bsp/include/nm_bsp_samd21_app.h"
#include "common/include/nm_common.h"

#define BSP_MIN(x,y) ((x)>(y)?(y):(x))


#define SW1_PIN
#define SW1_MUX
#define SW1_LINE 

#ifdef WING_BOARD_WITH_LEDS_BUTTON
#define SW2_LINE	    3
#define SW2_PIN			PIN_PB03
#define SW2_MUX			MUX_PB03A_EIC_EXTINT3
#endif /* WING_BOARD_WITH_LEDS_BUTTON */

/*
   ---------------------------------
   ------ Module Pin Settings ------
   ---------------------------------
*/

#define LONG_PRESS_TIME			(1500/TICK_RES)	// ~2 sec
#define DEBOUNCE_TIME			(40/TICK_RES)	// ~50ms

/*
* Structure
*
*/
typedef struct
{
	tpfNmBspTimerCb	pfCb;
	uint32 u32Timeout;
	uint32 u32Period;
} tstrTimer;


typedef struct
{
	tstrTimer strTimer;
	uint8 u8Enabled;
} tstrWakeTimer;
/**
*
* Global variables
*/
uint32 gu32Jiffies1ms;
uint32 gu32Jiffies20ms;


static uint16 gu16Btn1Cnt, gu16Btn2Cnt;
static tpfNmBspBtnPress gpfBtns;
static uint8 gu8BtnIfg;
static tstrTimer gstrTimer20ms, gstrTimer1ms, gstrConfigurableTimer;
#if (defined _STATIC_PS_)||(defined _DYNAMIC_PS_)
static tstrWakeTimer gstrWakeTimer;
#endif

struct tcc_module tcc_instance;
struct tcc_module configurable_tcc;
/**
*
* Static functions
*/
static void btn_poll(void)
{
	bool btn_inactive;
	if (gu8BtnIfg & SW1) {
		if (gu16Btn1Cnt <= LONG_PRESS_TIME) {
			gu16Btn1Cnt++;
		}
		if (gu16Btn1Cnt == LONG_PRESS_TIME) {
			gpfBtns(SW1, 1); /* long press callback */
		}
		btn_inactive = (port_pin_get_input_level(BUTTON_0_PIN) == BUTTON_0_INACTIVE);
		if ((gu16Btn1Cnt >= DEBOUNCE_TIME) && (gu16Btn1Cnt < LONG_PRESS_TIME)
				&& btn_inactive) {
			gpfBtns(SW1, 0); /* Short press callback */
		}
		if (btn_inactive)
		{
			gu8BtnIfg &= ~SW1;
			gu16Btn1Cnt = 0;
			extint_chan_enable_callback(BUTTON_0_EIC_LINE, EXTINT_CALLBACK_TYPE_DETECT);
		}
	}

#ifdef WING_BOARD_WITH_LEDS_BUTTON
	if (gu8BtnIfg & SW2) {
		if (gu16Btn2Cnt <= LONG_PRESS_TIME) {
			gu16Btn2Cnt++;
		}
		if (gu16Btn2Cnt == LONG_PRESS_TIME) {
			gpfBtns(SW2, 1); /* long press callback */
		}
		btn_inactive = (port_pin_get_input_level(SW2_PIN) == BUTTON_0_INACTIVE);
		if ((gu16Btn2Cnt >= DEBOUNCE_TIME) && (gu16Btn2Cnt < LONG_PRESS_TIME)
				&& btn_inactive) {
			gpfBtns(SW2, 0); /* Short press callback */
		}
		if (btn_inactive)
		{
			gu8BtnIfg &= ~SW2;
			gu16Btn2Cnt = 0;
			extint_chan_enable_callback(SW2_LINE, EXTINT_CALLBACK_TYPE_DETECT);
		}
	}
#endif /* WING_BOARD_WITH_LEDS_BUTTON */
}

static void _tcc_callback_to_change_duty_cycle(struct tcc_module *const module_inst)
{
	gu32Jiffies1ms++;
	if(gstrTimer1ms.pfCb)
		gstrTimer1ms.pfCb();

	if(gu32Jiffies1ms%20 == 0)
	{
#ifdef _STATIC_PS_
		if((gstrWakeTimer.strTimer.pfCb)&&(gstrWakeTimer.u8Enabled))
		{
			gu32Jiffies20ms+=(TICK_RES_SLEEP/TICK_RES);
		}
else
#endif
		{
			gu32Jiffies20ms++;
		}
#ifdef _STATIC_PS_
		if(gstrWakeTimer.strTimer.pfCb)
		{
			if(NM_BSP_TIME_MSEC >= gstrWakeTimer.strTimer.u32Timeout)
			{
				nm_bsp_wake_ctrl(0);
				gstrWakeTimer.strTimer.pfCb();
				gstrWakeTimer.strTimer.u32Timeout = NM_BSP_TIME_MSEC + gstrWakeTimer.strTimer.u32Period;
			}
		}
#endif
		if(gstrTimer20ms.pfCb)
		{
			if(NM_BSP_TIME_MSEC >= gstrTimer20ms.u32Timeout)
			{
				gstrTimer20ms.pfCb();
				gstrTimer20ms.u32Timeout = NM_BSP_TIME_MSEC + gstrTimer20ms.u32Period;
			}
		}

		btn_poll();		
	}
}

/*
*	@fn			_tcc_configurable_timer_callback
*	@brief		Configurable Timer Callback
*	@date		08 October 2015
*	@version	1.0
*/

static void _tcc_configurable_timer_callback(struct tcc_module *const module_inst)
{
	if(gstrConfigurableTimer.pfCb)
		gstrConfigurableTimer.pfCb();
}


static void timer0_init(void)
{

	struct tcc_config config_tcc;
	tcc_get_config_defaults(&config_tcc, TCC0);

	//! [setup_change_config]
	config_tcc.counter.period = 750;
	config_tcc.counter.reload_action = TCC_RELOAD_ACTION_GCLK;
	config_tcc.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV64;
	tcc_init(&tcc_instance, TCC0, &config_tcc);
	tcc_enable(&tcc_instance);

	//! [setup_register_callback]
	tcc_register_callback(
	&tcc_instance,
	_tcc_callback_to_change_duty_cycle,
	TCC_CALLBACK_CHANNEL_0);
	
	tcc_enable_callback(&tcc_instance,
	TCC_CALLBACK_CHANNEL_0);
}

/*
*	@fn			configurable_timer_init
*	@brief		Initialize the Configurable Timer
*	@date		08 October 2015
*	@version	1.0
*/

static void configurable_timer_init(uint32_t u32Period)
{
	struct tcc_config config_tcc;
	tcc_get_config_defaults(&config_tcc, TCC1);
	M2M_DBG("Timer period: %lu\r\n", u32Period);

	//! [setup_change_config]
	config_tcc.counter.period = u32Period;
	tcc_init(&configurable_tcc, TCC1, &config_tcc);
	tcc_enable(&configurable_tcc);

	//! [setup_register_callback]
	tcc_register_callback(
	&configurable_tcc,
	_tcc_configurable_timer_callback,
	TCC_CALLBACK_OVERFLOW);
}


static void btn_isr(void)
{
	gu8BtnIfg |= SW1;
	extint_chan_disable_callback(BUTTON_0_EIC_LINE,
	EXTINT_CALLBACK_TYPE_DETECT);
}
#ifdef WING_BOARD_WITH_LEDS_BUTTON
static void btn2_isr(void)
{

	gu8BtnIfg |= SW2;
	extint_chan_disable_callback(SW2_LINE,
	EXTINT_CALLBACK_TYPE_DETECT);
}
#endif /* WING_BOARD_WITH_LEDS_BUTTON */

/*
*	@fn		nm_bsp_init
*	@brief	Initialize BSP
*	@return	0 in case of success and -1 in case of failure
*	@author	M.S.M
*	@date	11 July 2012
*	@version	1.0
*/
sint8 nm_bsp_app_init(void)
{
	gstrTimer20ms.pfCb = NULL;
	gstrTimer20ms.u32Timeout = 0;
	gstrTimer20ms.u32Period = 0;

#ifdef _STATIC_PS_
	gstrWakeTimer.strTimer.pfCb = NULL;
	gstrWakeTimer.strTimer.u32Timeout = 0;
	gstrWakeTimer.strTimer.u32Period = ((uint32)-1);
	gstrWakeTimer.u8Enabled = 0;
#endif

	gstrTimer1ms.pfCb = NULL;
	gstrTimer1ms.u32Timeout = 0;
	gstrTimer1ms.u32Period = 0;
	
	gstrConfigurableTimer.pfCb = NULL;
	gstrConfigurableTimer.u32Timeout = 0;
	gstrConfigurableTimer.u32Period = 0;
		
	timer0_init();
	
	return M2M_SUCCESS;
}

/*
*	@fn			nm_bsp_app_configurable_timer_init
*	@brief		Initialize the Configurable Timer
*	@date		08 October 2015
*	@version	1.0
*/
void nm_bsp_app_configurable_timer_init(uint32_t u32Period)
{
	configurable_timer_init(u32Period);	
}

/**
*	@fn		nm_bsp_deinit
*	@brief	De-iInitialize BSP
*	@return	0 in case of success and -1 in case of failure
*	@author	M. Abdelmawla
*	@date	11 July 2012
*	@version	1.0
*/
sint8 nm_bsp_app_deinit(void)
{
	return M2M_SUCCESS;
}

/*
*	@fn		nm_bsp_btn_init
*	@brief	Initialize buttons driver
*	@author	M.S.M
*	@date	28 OCT 2013
*	@version	1.0
*/

void nm_bsp_btn_init(tpfNmBspBtnPress pfBtnCb)
{
	//struct port_config pin_conf;
	struct extint_chan_conf config_extint_chan;
		
	gpfBtns = pfBtnCb;
	gu8BtnIfg = 0;
	gu16Btn1Cnt = 0;
	gu16Btn2Cnt = 0;

#ifdef WING_BOARD_WITH_LEDS_BUTTON	
	port_get_config_defaults(&pin_conf);

	/* Set buttons as inputs */
	pin_conf.direction  = PORT_PIN_DIR_INPUT;
	pin_conf.input_pull = PORT_PIN_PULL_UP;
	port_pin_set_config(SW2_PIN, &pin_conf);

	
	/*Configure SW1*/
	extint_chan_get_config_defaults(&config_extint_chan);

	config_extint_chan.gpio_pin           = SW2_PIN;
	config_extint_chan.gpio_pin_mux       = SW2_MUX;
	config_extint_chan.gpio_pin_pull      = EXTINT_PULL_UP;
	config_extint_chan.detection_criteria = EXTINT_DETECT_FALLING;

	extint_chan_set_config(SW2_LINE, &config_extint_chan);

	extint_register_callback(btn2_isr,
	SW2_LINE,
	EXTINT_CALLBACK_TYPE_DETECT);
	extint_chan_enable_callback(SW2_LINE,
	EXTINT_CALLBACK_TYPE_DETECT);
#endif /* WING_BOARD_WITH_LEDS_BUTTON */

	/*Configure SW2*/
	extint_chan_get_config_defaults(&config_extint_chan);

	config_extint_chan.gpio_pin           = BUTTON_0_EIC_PIN;
	config_extint_chan.gpio_pin_mux       = BUTTON_0_EIC_MUX;
	config_extint_chan.gpio_pin_pull      = EXTINT_PULL_UP;
	config_extint_chan.detection_criteria = EXTINT_DETECT_FALLING;

	extint_chan_set_config(BUTTON_0_EIC_LINE, &config_extint_chan);

	extint_register_callback(btn_isr,
	BUTTON_0_EIC_LINE,
	EXTINT_CALLBACK_TYPE_DETECT);

	extint_chan_enable_callback(BUTTON_0_EIC_LINE,
	EXTINT_CALLBACK_TYPE_DETECT);

}

/*
*	@fn		nm_bsp_uart_sendnm_bsp_uart_send
*	@author	M.S.M
*	@date	28 OCT 2013
*	@version	1.0
*/
void nm_bsp_uart_send(const uint8 *pu8Buf, uint16 u16Sz)
{

}
/**
*	@fn		nm_bsp_start_timer
*	@brief	Start 20ms timer
*	@author	M.S.M
*	@date	28 OCT 2013
*	@version	1.0
*/
void nm_bsp_start_timer(tpfNmBspTimerCb pfCb, uint32 u32Period)
{
	gstrTimer20ms.pfCb = pfCb;
	gstrTimer20ms.u32Timeout = u32Period+ NM_BSP_TIME_MSEC;
	gstrTimer20ms.u32Period = u32Period;
}

/*
*	@fn			nm_bsp_start_1ms_timer
*	@brief		Start 1ms timer
*	@date		08 October 2015
*	@version	1.0
*/
void nm_bsp_start_1ms_timer(tpfNmBspTimerCb pfCb)
{
	gstrTimer1ms.pfCb = pfCb;
}

/*
*	@fn			nm_bsp_start_configurable_timer
*	@brief		Start configurable timer
*	@date		08 October 2015
*	@version	1.0
*/
void nm_bsp_start_configurable_timer(tpfNmBspTimerCb pfCb)
{
	tcc_enable_callback(&configurable_tcc, TCC_CALLBACK_OVERFLOW);
	gstrConfigurableTimer.pfCb = pfCb;
}

/**
*	@fn		nm_bsp_stop_timer
*	@brief	Start 20ms timer
*	@author	M.S.M
*	@date	28 OCT 2013
*	@version	1.0
*/
void nm_bsp_stop_timer(void)
{
	gstrTimer20ms.pfCb = NULL;
}

/*
*	@fn			nm_bsp_stop_1ms_timer
*	@brief		Stop 1ms timer
*	@date		08 October 2015
*	@version	1.0
*/
void nm_bsp_stop_1ms_timer(void)
{
	gstrTimer1ms.pfCb = NULL;
}

/*
*	@fn			nm_bsp_stop_configurable_timer
*	@brief		Stop configurable timer
*	@date		08 October 2015
*	@version	1.0
*/
void nm_bsp_stop_configurable_timer(void)
{
	gstrConfigurableTimer.pfCb = NULL;
	tcc_disable_callback(&configurable_tcc, TCC_CALLBACK_OVERFLOW);
	tcc_disable(&configurable_tcc);
}

#ifdef _STATIC_PS_
/**
*	@fn		nm_bsp_register_wake_isr
*	@brief	REGISTER wake up timer 
*	@author	M.S.M
*	@date	28 OCT 2013
*	@version	1.0
*/
void nm_bsp_register_wake_isr(tpfNmBspIsr pfIsr,uint32 u32MsPeriod)
{

	gstrWakeTimer.strTimer.pfCb = pfIsr;
	gstrWakeTimer.strTimer.u32Timeout = u32MsPeriod + NM_BSP_TIME_MSEC;
	gstrWakeTimer.strTimer.u32Period = u32MsPeriod;
	gstrWakeTimer.u8Enabled = 0;
}
/**
*	@fn		nm_bsp_wake_ctrl
*	@brief	control wake up timer
*	@author	M.S.M
*	@date	28 OCT 2013
*	@version	1.0
*/
void nm_bsp_wake_ctrl(uint8 en)
{
	gstrWakeTimer.u8Enabled = en;
	if(en)
	{
		gstrWakeTimer.strTimer.u32Timeout = gstrWakeTimer.strTimer.u32Period + NM_BSP_TIME_MSEC;
	}
}
#endif
#if (defined _STATIC_PS_)||(defined _DYNAMIC_PS_)
/**
*	@fn		nm_bsp_enable_mcu_ps
*	@brief	Start POWER SAVE FOR MCU 
*	@author	M.S.M
*	@date	28 OCT 2013
*	@version	1.0
*/
void nm_bsp_enable_mcu_ps(void)
{
	if(!gu8BtnIfg)
	{
		if(gstrWakeTimer.u8Enabled)
		{

		}
	}
}
#endif


