/*
 * $LastChangedRevision: 1603 $
 * $LastChangedDate:: 2019-01-21 19:02:13 +0100#$
 *
 * This file is part of X2C. http://x2c.lcm.at/
 *
 * Copyright (c) 2016, Linz Center of Mechatronics GmbH (LCM) http://www.lcm.at/
 * All rights reserved.
 */
/*
 * This file is licensed according to the BSD 3-clause license as follows:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the "Linz Center of Mechatronics GmbH" and "LCM" nor
 *       the names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL "Linz Center of Mechatronics GmbH" BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "Target.h"
#include "SerialGeneric.h"
#include "Hardware.h"

/*
 * Sample times
 */
#define SAMPLETIME_100US (10000)
#define SAMPLETIME_50US (20000)
#define SAMPLETIME_20US (50000)
#define SAMPLETIME_10US (100000)

/** Sample time */
#define SELECTED_SAMPLETIME		SAMPLETIME_100US


/* private prototypes */
static void sendSerial(tSerial* serial, uint8 data);
static uint8 receiveSerial(tSerial* serial);
static uint8 isReceiveDataAvailable(tSerial* serial);
static uint8 isSendReady(tSerial* serial);


/**
 * @brief Initialization of hardware.
 */
void initHardware(void)
{
	/*------------------------------------------------------------------------*/
	/** - Configuration of clock and DC-DC regulator */
	/*------------------------------------------------------------------------*/
	EMU_DCDCInit_TypeDef dcdcInit = EMU_DCDCINIT_DEFAULT;//EMU_DCDCINIT_STK_DEFAULT;
	CMU_HFXOInit_TypeDef hfxoInit = CMU_HFXOINIT_DEFAULT;//CMU_HFXOINIT_STK_DEFAULT;

	/* Chip errata */
	CHIP_Init();

	/* Init DCDC regulator and HFXO with kit specific parameters */
	EMU_DCDCInit(&dcdcInit);
	CMU_HFXOInit(&hfxoInit);

	/* Switch HFCLK to HFXO and disable HFRCO */
	CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO);
	CMU_OscillatorEnable(cmuOsc_HFRCO, false, false);

	/* enable clock for peripherals */
	CMU_ClockEnable(cmuClock_HFPER, true);

	/* enable clock for GPIO */
	CMU_ClockEnable(cmuClock_GPIO, true);

    /*------------------------------------------------------------------------*/
    /** - Configuration of SysTick Timer
     *    - 100 us system tick as X2C sample time
     *    - Generation of cyclic interrupt with selected sample time
     *    - Interrupt calls X2C main task
     *    .
     */
    /*------------------------------------------------------------------------*/
	if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / SAMPLETIME_100US)) while (1) ;


    /*------------------------------------------------------------------------*/
    /** - Configuration of IO ports */
    /*------------------------------------------------------------------------*/
	GPIO_PinModeSet(gpioPortF, 4, gpioModePushPull, 0);			/* output PF4: LED0 */
	GPIO_PinModeSet(gpioPortF, 5, gpioModePushPull, 1); 		/* output PF5: LED1 */
	GPIO_PinModeSet(gpioPortF, 6, gpioModeInputPullFilter, 1);	/* input PF6: PB0 (pull-up activated -> active low) */
	GPIO_PinModeSet(gpioPortF, 7, gpioModeInputPullFilter, 1);	/* input PF7: PB1 (pull-up activated -> active low) */

    /*------------------------------------------------------------------------*/
    /** - Configuration of UART
     *    - Baudrate: 115200 bps
     *    - Data bits: 8
     *    - Parity: none
     *    - Stop bits: 1
     *    .
     */
    /*------------------------------------------------------------------------*/
	/* enable USART clock */
	CMU_ClockEnable(cmuClock_USART0, true);

	/* initialize USART with default values */
	USART_InitAsync_TypeDef usartInit = USART_INITASYNC_DEFAULT;
	usartInit.enable       = usartDisable;   /* don't enable UART upon initialization */
	USART_InitAsync(USART0, &usartInit);

	/* configure UART pins and enable VCP */
	GPIO_PinModeSet(gpioPortA, 0, gpioModePushPull, 1);			/* output PA0: Tx */
	GPIO_PinModeSet(gpioPortA, 1, gpioModeInput, 0);			/* input PA1: Rx */
	GPIO_PinModeSet(gpioPortA, 5, gpioModePushPull, 1);			/* output PA5: enable USART0 as virtual COM port */

	/* enable USART pins */
	USART0->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN;	/* enable Rx and Tx pin */

	/* set pin location */
	USART0->ROUTELOC0 = USART_ROUTELOC0_RXLOC_LOC0 | USART_ROUTELOC0_TXLOC_LOC0;

	/* enable USART */
	USART_Enable(USART0, usartEnable);
}


/**
 * @brief Initialization of serial interface.
 *
 * @param serialP Serial object
 */
void initSerial(tSerial* serialP)
{
    serialP->send = (void (*)(tInterface*, uint8))sendSerial;
    serialP->receive = (uint8 (*)(tInterface*))receiveSerial;
    serialP->isReceiveDataAvailable = (uint8 (*)(tInterface*))isReceiveDataAvailable;
    serialP->isSendReady = (uint8 (*)(tInterface*))isSendReady;
}

/**
 * @brief Routine to send data over serial interface.
 *
 * @param serial Serial interface object.
 * @param data Data byte to send.
 */
static void sendSerial(tSerial* serial, uint8 data)
{
	while (((USART0->STATUS) & USART_STATUS_TXIDLE) != USART_STATUS_TXIDLE);
	USART0->TXDATA = data;
}

/**
 * @brief Routine to fetch data from the serial interface.
 *
 * @param serial Serial interface object.
 * @return Received data byte.
 */
static uint8 receiveSerial(tSerial* serial)
{
    return USART0->RXDATA;
}

/**
 * @brief Routine to check if data from the serial interface is available.
 *
 * @param serial Serial interface object.
 * @return 1 when data is available, 0 otherwise.
 */
static uint8 isReceiveDataAvailable(tSerial* serial)
{
	uint8 retVal = 0;	/* default: receive buffer is empty */

	if (((USART0->STATUS) & USART_STATUS_RXDATAV) == USART_STATUS_RXDATAV)
	{
		/* data is available in the receive buffer */
		retVal = 1;
	}

	return retVal;
}

/**
 * @brief Routine to check if data can be send over the serial interface.
 *
 * @param serial Serial interface object.
 * @return 1 when data can be send, 0 otherwise.
 */
static uint8 isSendReady(tSerial* serial)
{
	uint8 retVal = 0;	/* default: transmitter is active */

	if (((USART0->STATUS) & USART_STATUS_TXIDLE) == USART_STATUS_TXIDLE)
	{
		/* transmitter is idle */
		retVal = 1;
	}

	return retVal;
}
