//******************************************************************************
//! @ProjectName: iSTP
//! @ModuleName:  init.c
//!
//! @Purpose:
//! This module provides initialization of iSTP mainboard
//!
//! Honeywell Proprietary
//!
//! @Copyright 2016 Honeywell SGN. All rights reserved.
//!
//! SVN revision information:
//! @version  $Revision: 2035 $
//! @author   $Author: Maximilian Tydor $
//! @date     $Date: 2016-11-14 10:02:34 +0100 (Mon, 14 Nov 2016) $
//******************************************************************************

//******************************************************************************
//  Include(s) for External Component API(s)
//******************************************************************************

//******************************************************************************
// Include(s) for Common Component API(s)
//******************************************************************************
#include "init.h"
#include "toggle.h"
#include "spi.h"
#include "sysclk.h"
#include "pmc.h"
#include "tc.h"
#include "core_cm4.h"
#include "usart.h"
#include "sam_gpio/sam_gpio.h"
#include "interrupt/interrupt_sam_nvic.h"
#include "eeprom.h"
#include <ISTPManager.h>
#include <powerlinemanager.h>

//******************************************************************************
//! @fn void board_init(void)
//!
//! @description
//!
//!
//! @param    none
//!
//! @return   none
//!
//! @calls    SPI_resetAllCs, sysclk_get_cpu_hz,  pmc_enable_periph_clk,
//!			  tc_find_mck_divisor, tc_init, tc_write_rc, NVIC_EnableIRQ
//!
//! @req
//!
//! @example
//!  Init iSTP board
//! @code
//!  board_init();
//! @endcode
//******************************************************************************
void board_init(void)
{
	cpu_irq_enable(); //enable cpu interrupt
	
	// Enable watchdog with pre-defined parameters
	wdt_init(WDT, WDT_MODE, WDT_CNTR_VALUE, WDT_DELTA_VALUE );
	
	
	// Power Lines Switches
	PIOB->PIO_PER =  PWR_3V3|PWR_5VD|PWR_5VA|PWR_EXT;	// Set pins as GPIO
	PIOB->PIO_OER =  PWR_3V3|PWR_5VD|PWR_5VA|PWR_EXT;	// Set pins as outputs
	PIOB->PIO_PUDR = PWR_3V3|PWR_5VD|PWR_5VA|PWR_EXT;	// Disable pull-ups
	PIOB->PIO_OWER = PWR_3V3|PWR_5VD|PWR_5VA|PWR_EXT;	// Enable output for writing
	PIOB->PIO_SODR = PWR_3V3|PWR_5VD|PWR_5VA|PWR_EXT;	// Set default values
	
    
	#ifdef MAINBOARD40
	// User LEDs
	PIOA->PIO_PER =  LED_R|LED_C|LED_L;
	PIOA->PIO_OER =  LED_R|LED_C|LED_L;
	PIOA->PIO_PUDR = LED_R|LED_C|LED_L;
	PIOA->PIO_OWER = LED_R|LED_C|LED_L;
	PIOA->PIO_CODR = LED_R|LED_C|LED_L;
	// Board (chip) Select GPIOs and decoder signals
	PIOC->PIO_PER =  CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C;
	
	PIOC->PIO_OER =  CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C;
	
	PIOC->PIO_PUDR = CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C;
	
	PIOC->PIO_OWER = CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C;
	#endif
	
	#ifdef MAINBOARD54
	// User LEDs
	PIOA->PIO_PER =  LED_R|LED_C|LED_L|CS_IMU|CS_HUM;
	PIOA->PIO_OER =  LED_R|LED_C|LED_L|CS_IMU|CS_HUM;
	PIOA->PIO_PUDR = LED_R|LED_C|LED_L|CS_IMU|CS_HUM;
	PIOA->PIO_OWER = LED_R|LED_C|LED_L|CS_IMU|CS_HUM;
	PIOA->PIO_CODR = LED_R|LED_C|LED_L;
	
	PIOC->PIO_PER =  LED_14|LED_15|LED_16;
	PIOC->PIO_OER =  LED_14|LED_15|LED_16;
	PIOC->PIO_PUDR = LED_14|LED_15|LED_16;
	PIOC->PIO_OWER = LED_14|LED_15|LED_16;
	PIOC->PIO_CODR = LED_14|LED_15|LED_16;
		
	// Board (chip) Select GPIOs and decoder signals
	PIOC->PIO_PER =  CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C|CS_ADC;
		
	PIOC->PIO_OER =  CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C|CS_ADC;
		
	PIOC->PIO_PUDR = CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C|CS_ADC;
		
	PIOC->PIO_OWER = CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C|CS_ADC;
	
	// SPI signals drivers enable pins
	EN_AXIS_A_PORT->PIO_PER = EN_AXIS_A_PIN;
	EN_AXIS_A_PORT->PIO_OER = EN_AXIS_A_PIN;
	EN_AXIS_A_PORT->PIO_PUDR = EN_AXIS_A_PIN;
	EN_AXIS_A_PORT->PIO_OWER = EN_AXIS_A_PIN;
	
	EN_AXIS_B_PORT->PIO_PER = EN_AXIS_B_PIN;
	EN_AXIS_B_PORT->PIO_OER = EN_AXIS_B_PIN;
	EN_AXIS_B_PORT->PIO_PUDR = EN_AXIS_B_PIN;
	EN_AXIS_B_PORT->PIO_OWER = EN_AXIS_B_PIN;
	
	EN_AXIS_C_PORT->PIO_PER = EN_AXIS_C_PIN;
	EN_AXIS_C_PORT->PIO_OER = EN_AXIS_C_PIN;
	EN_AXIS_C_PORT->PIO_PUDR = EN_AXIS_C_PIN;
	EN_AXIS_C_PORT->PIO_OWER = EN_AXIS_C_PIN;
	
	#else
	// User LEDs
	PIOA->PIO_PER =  LED_R|LED_C|LED_L|CS_IMU;
	PIOA->PIO_OER =  LED_R|LED_C|LED_L|CS_IMU;
	PIOA->PIO_PUDR = LED_R|LED_C|LED_L|CS_IMU;
	PIOA->PIO_OWER = LED_R|LED_C|LED_L|CS_IMU;
	PIOA->PIO_CODR = LED_R|LED_C|LED_L;
	
	// Board (chip) Select GPIOs and decoder signals
	PIOC->PIO_PER =  CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C|CS_ADC;
	
	PIOC->PIO_OER =  CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C|CS_ADC;
	
	PIOC->PIO_PUDR = CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C|CS_ADC;
	
	PIOC->PIO_OWER = CS_B0|CS_B1|CS_B2|CS_B3|CS_B4|CS_B5|
	CS_A0|CS_A1|CS_A2|CS_A3|CS_A4|CS_A5|
	CS_C0|CS_C1|CS_C2|CS_C3|CS_C4|CS_C5|
	DEC_A|DEC_B|DEC_C|CS_ADC;
	#endif
    
    // SPI module needs to know peripheral clock prior
    // first use.
    SPI_UpdatePeriphClk();
    // SPI master init is here just to enable SPI periphery prior
    // configuration of SPI pins to peripheral function.
    SPI_master_init(EEPROM_SPI_FREQ_HZ, SPI_POL_0, SPI_PHA_0, SPI_8_BIT, 0);
    // Deactivate all chip selects    
	SPI_resetAllCs();
	
	// Master SPI (Sensor-boards interface)
	PIOA->PIO_PDR =  MSPI_MISO|MSPI_MOSI|MSPI_SCLK;
	
	#ifndef MAINBOARD54
	// USB VBUS monitoring pin
	PMC->PMC_PCER0 = (1<<ID_PIOA);
	PIOA->PIO_PER = VBUS;
	PIOA->PIO_PUDR = VBUS;
	PIOA->PIO_IER = VBUS;
	#endif //NOT MAINBOARD54
	
	/* Configure USART HW handshaking pins */
	gpio_configure_pin(PIN_USART1_CTS_IDX, PIN_USART1_CTS_FLAGS);
			
	/* Configure USART RTS pin */
	gpio_configure_pin(PIN_USART1_RTS_IDX, PIN_USART1_RTS_FLAGS);
		
	/* Configure USART TXD pin */
	gpio_configure_pin(PIN_USART1_TXD_IDX, PIN_USART1_TXD_FLAGS);
		
	/* Configure USART RXD pin */
	gpio_configure_pin(PIN_USART1_RXD_IDX, PIN_USART1_RXD_FLAGS);

    /* Configure UART0 RXD and TXD pin */
    gpio_configure_pin(PIN_UART0_RXD_IDX, PIN_UART0_RXD_FLAGS);
    gpio_configure_pin(PIN_UART0_TXD_IDX, PIN_UART0_TXD_FLAGS);

    // Switch SCLK to output of 32.768kHz crystal oscillator if
    // XTAL 32.768kHz is available on board.
    // 32.768kHz XTAL provides better clock stability than default internal RC
    // oscillator used as SCLK source.
    // SCLK is used e.g. for watchdog.
    // All main board HW revisions other than 4.0 and 5.1 has 32.768kHz XTAL
    // assembled
#if ( ( !defined(MAINBOARD40) ) && ( !defined(MAINBOARD51) ) )
    // Following function triggers the sequence:
    // - Configure XIN32, XOUT32 pins for XTAL operation
    // - Enable XTAL oscillator
    // - Wait until XTAL oscillator is stable
    // - Glitch-free switch of the SCLK to XTAL instead of internal RC
    // - Disable internal RC
    pmc_switch_sclk_to_32kxtal(0);
    // Wait until SCLK is switched to XTAL oscillator
    while( !pmc_osc_is_ready_32kxtal() )
    {
        // Wait until 32kHz XTAL oscillator is ready
    }
#endif

}

static uint32_t TC0_div = 0;
static volatile	uint32_t frequency = 0;
static volatile	uint32_t mclk = 0;

static volatile uint64_t timeStamp = 0;

void resetTick(void)
{
	timeStamp = 0;
}

uint64_t getTick(void)
{
	return timeStamp;
}

uint32_t getMinor(void)
{
	return tc_read_cv(TC0, 0);
}

double getTimeSince(void)
{
	return (getTick() * ((mclk/TC0_div)/frequency)  + getMinor()) / (double)(mclk/TC0_div);
}

void initalizeTimers(uint32_t freq)
{
	resetTick();
	frequency = freq;
	// TC common parameters
	mclk = sysclk_get_cpu_hz();
	// TC0 100Hz setup with interrupt handler
	pmc_enable_periph_clk(ID_TC0);
	uint32_t TC0_clks = 0;
	tc_find_mck_divisor(frequency, mclk, &TC0_div, &TC0_clks, mclk);
	tc_init(TC0, 0, TC0_clks | TC_CMR_CPCTRG);
	tc_write_rc(TC0, 0, (mclk/TC0_div)/frequency);
	NVIC_EnableIRQ((IRQn_Type) ID_TC0);
	tc_enable_interrupt(TC0, 0, TC_IER_CPCS);
	tc_start(TC0, 0);
}



void TC0_Handler(void)
{
	static uint32_t safetyTickCounter = 0;
    uint32_t dummy;
	dummy = tc_get_status(TC0, 0);
	(void) dummy;
	
	timeStamp++;

    if(ISTPMGetSamplingStatus() == ISTP_SAMPLING_ACTIVE)
    {
        if( ISTPMSafetyCheckPointGet() == 1 )
        {
            // Safety checkpoint passed
            // Clear the counter of non-passed ticks
            safetyTickCounter = 0;
            // Clear the checkpoint
            ISTPMSafetyCheckPointReset();
        }
        else
        {
            safetyTickCounter++;
            if(safetyTickCounter >= SAFETY_CHKPT_NON_PASSED_TICKS )
            {
                // Scheduler loop didn't pass through for more than specified
                // number of scheduler ticks.
                // Force reset of the device
                rstc_start_software_reset(RSTC);
                while(1)
                {
                    // Just wait until "force restarted" by previous function or
                    // by WDT if forced reset didn't work.
                }
            }
        }
    }
    else
    {
        // If sampling is inactive, just let the HW watchdog do the job.
        // The only safety action is to turn OFF the "high power" power supply
        // rail.
        safetyTickCounter = 0;
        PLMswitchRail( POWER_RAIL_EXT, POWER_RAIL_OFF, 0 );
    }
}

#ifndef MAINBOARD54
//******************************************************************************
//! @fn void VBUS_Handler (void)
//!a
//! @description
//! VBUS interrupt
//!
//! @param    None
//!
//! @return   None
//!
//! @calls    None
//!
//! @req
//!
//! @example 
//! 
//! @code
//! 
//! @endcode
//******************************************************************************
void VBUS_Handler (void)
{
	if(PIOA->PIO_PDSR & VBUS)
  {
		udc_attach();
	}
	else
  {
		udc_detach();
	}		

}
#endif //NOT MAINBOARD54
