/*This file is prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
 *
 * \brief Ultrasound Positioning System Receiver application.
 *
 * - Compiler:           GNU GCC for AVR32
 * - Supported devices:  USPSR Rev. 2B board with AT32UC3C1256 microcontroller.
 *
 * \author               Alexandros Soumelidis\n
 *                       System and Control Lab\n
 *                       Computer and Automation Research Institute\n
 *                       of the Hungarian Academy of Sciences (MTA SZTAKI)\n
 *                       http://www.sztaki.hu/~scl
 *
 ******************************************************************************/

/*! \page License
 * Copyright (c) 2010 MTA SZTAKI. All rights reserved.
 * Copyright (c) 2010 Alexandros Soumelidis. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The name of SZTAKI may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with USPSR
 * hardware, product of MTA SZTAKI.
 *
 * THIS SOFTWARE IS PROVIDED BY SZTAKI "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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
 *
 */

/*! \mainpage
 * \section intro Introduction
 * This is the documentation of the software belonging to a Receiver application
 * to be used in an Ultrasound Positioning System (USPS). The application runs
 * on a custom board USPSR, built in the Systems and Control Lab (SZTAKI).
 * The application measures the distance of the US receiver from different US
 * sources, and on this basis derives its position by applying trilateration
 * algorithms. Synchronization and source identification is realized by radio
 * signals generated by an FSK RF transmitter operating in the 868 MHz ISM
 * band.
 *
 * \section files Main Files
 * - usart.c: USART driver;
 * - usart.h: USART driver header file;
 * - usps2b.c: main module of the USPSR application.
 *
 * \section compilinfo Compilation Information
 * This software is written for GNU GCC for AVR32.
 * Other compilers may or may not work.
 *
 * \section deviceinfo Device Information
 * USPSR V2B board with AT32UC3C1256 microcontroller.
 *
 * \section configinfo Configuration Information
 * This program has been tested with the following configuration:
 * - USPSR 2B Ultrasound Positioning Receiver board with power supply 7-9 V DC
 * - CPU clock: 8 MHz
 * - USART2 connected to a PC serial port via an RS232 transciever module
 *   (3.3 V type) and standard RS232 DB9 cable, terminal settings:
 *   - 57600 bps,
 *   - 8 data bits,
 *   - no parity bit,
 *   - 1 stop bit,
 *   - no flow control.
 * - USART0 Rx internally connected to a Telecontrolli 868 MHz RF receiver
 *   module output, terminal settings:
 *   - 1200 bps,
 *   - 9 data bits,
 *   - even parity,
 *   - 1 stop bit,
 *   - no flow control.
 * - AD0 analog input is internally connected to the RSSI output of the RF
 *   receiver
 * - A2 Timer/Counter input line internally connected to the Ultrasound Receiver
 *   module output
 * - SPI MOSI, SCK and NPCS0 internally connected to the corresponding lines of
 *   an MCP41010 (Microchip) digital potmeter
 * - GPIO20-21 outputs internally connected to LED1, LED2 yellow LEDs
 * - GPIO22-23 outputs internally connected to LED3, LED4 red LEDs
 *
 * \section contactinfo Contact Information
 * For further information, visit
 * <A href="http://www.sztaki.com/~scl">.
 */


#include <avr32/io.h>
#include "compiler.h"
#if defined (__GNUC__)
#  include "intc.h"
#endif
#include "board.h"
#include "pm.h"
#include "gpio.h"
#include "usart.h"
#include "tc.h"
#include "flashc.h"
#include "spi.h"
#include "nlao_cpu.h"
#include "pwm.h"
#include "adc.h"

/*! \brief Variables
 */

volatile static int print_sec = 1;
volatile U32 tc_tick = 0;
volatile static signed short adc_curr_value, adc_emf_value;
/*! \brief TC interrupt.
 */
#if defined (__GNUC__)
__attribute__((__interrupt__))
#elif defined (__ICCAVR32__)
#pragma handler = USPSR_TC_IRQ_GROUP, 1
__interrupt
#endif
static void tc_irq(void)
{
  // Increment the ms seconds counter
  tc_tick++;

  // Clear the interrupt flag. This is a side effect of reading the TC SR.
  tc_read_sr(USPSR_TC, USPSR_TC_CHANNEL);

  // specify that an interrupt has been raised
  print_sec = 1;
}

static void pwm_interrupt(void)
{
	
	adc_emf_value=adc_get_value(ADC_BASE, ADC_PIN_EMF);
	
	avr32_pwm_isr_t isr;
	isr=AVR32_PWM.ISR;
}

/*! \brief Converts the given number to an ASCII decimal representation.
 */
static char *print_i(char *str, int n)
{
    int i = 10;

    str[i] = '\0';
    do
    {
      str[--i] = '0' + n%10;
      n /= 10;
    }while(n);

    return &str[i];
}


/*! \brief Main function of the USPSR application
 *  - Configure the CPU to run at 60MHz
 *  - Configure the USART
 *  - Register the TC interrupt (GCC only)
 *  - Configure, enable the CPCS (RC compare match) interrupt, and start a TC channel in waveform mode
 *  - In an infinite loop, update the USART message every second.
 */


int main(void)
{
	
	
	 
	 
	  char temp[20];
	  char *ptemp;

	  volatile avr32_pm_t* pm = &AVR32_PM;
	  volatile avr32_tc_t *tc = USPSR_TC;



	//////////////////////// Options for waveform generation.
	  static const tc_waveform_opt_t WAVEFORM_OPT =
	  {
	    .channel  = USPSR_TC_CHANNEL,                  // Channel selection.

	    .bswtrg   = TC_EVT_EFFECT_NOOP,                // Software trigger effect on TIOB.
	    .beevt    = TC_EVT_EFFECT_NOOP,                // External event effect on TIOB.
	    .bcpc     = TC_EVT_EFFECT_NOOP,                // RC compare effect on TIOB.
	    .bcpb     = TC_EVT_EFFECT_NOOP,                // RB compare effect on TIOB.

	    .aswtrg   = TC_EVT_EFFECT_NOOP,                // Software trigger effect on TIOA.
	    .aeevt    = TC_EVT_EFFECT_NOOP,                // External event effect on TIOA.
	    .acpc     = TC_EVT_EFFECT_NOOP,                // RC compare effect on TIOA: toggle.
	    .acpa     = TC_EVT_EFFECT_NOOP,                // RA compare effect on TIOA: toggle (other possibilities are none, set and clear).

	    .wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,// Waveform selection: Up mode with automatic trigger(reset) on RC compare.
	    .enetrg   = FALSE,                             // External event trigger enable.
	    .eevt     = 0,                                 // External event selection.
	    .eevtedg  = TC_SEL_NO_EDGE,                    // External event edge selection.
	    .cpcdis   = FALSE,                             // Counter disable when RC compare.
	    .cpcstop  = FALSE,                             // Counter clock stopped with RC compare.

	    .burst    = FALSE,                             // Burst signal selection.
	    .clki     = FALSE,                             // Clock inversion.
	    .tcclks   = TC_CLOCK_SOURCE_TC3                // Internal source clock 3, connected to fPBA / 8.
	  };





//////////SPI STATUS////////////////////////

  void spi_report(spi_status_t stat) 
{ 
   switch (stat) 
   { 
   case SPI_ERROR: 
   //  usart_write_line(USPSR_COM_USART, "Error ");
      break; 
   case SPI_OK: 
   // usart_write_line(USPSR_COM_USART, "SPI OK ");
      break; 
   case SPI_ERROR_TIMEOUT: 
   //  usart_write_line(USPSR_COM_USART, "Timeout ");
      break; 
   case SPI_ERROR_ARGUMENT: 
    // usart_write_line(USPSR_COM_USART, "Error argument "); 
      break; 
   case SPI_ERROR_OVERRUN: 
    // usart_write_line(USPSR_COM_USART, "Error overrun ");
      break; 
   case SPI_ERROR_MODE_FAULT: 
   //  usart_write_line(USPSR_COM_USART, "Mode fault ");
      break; 
   case SPI_ERROR_OVERRUN_AND_MODE_FAULT: 
    // usart_write_line(USPSR_COM_USART, "Overrun and mode fault ");
      break; 
   } 
} 


////////////////GPIO////////////////////////////

static const gpio_map_t SPI_GPIO_MAP=
{
	 {SPI_SCK_PIN,SPI_SCK_FUNCTION},
    {SPI_MISO_PIN,SPI_MISO_FUNCTION},
	{SPI_NPCS_PIN,SPI_NPCS_FUNCTION}	
};


//////////////////////PWM////////////////////
static const gpio_map_t PWM_GPIO_MAP=
{
	 {PWM_PIN,PWM_FUNCTION}
   	
};
//////////////////////USART//////////////////////////
 static const gpio_map_t USART_GPIO_MAP =
  {
    {USPSR_COM_USART_RX_PIN, USPSR_COM_USART_RX_FUNCTION},
    {USPSR_COM_USART_TX_PIN, USPSR_COM_USART_TX_FUNCTION}
  };
////////////////ADC///////////////////////
static const gpio_map_t ADC_GPIO_MAP=
{
	{ADC_PIN_EMF, ADC_FUNCT_EMF},
	{ADC_PIN_CURR, ADC_FUNCT_CURR}			
};


////////////////////////TC_INTERRUPT////////////////////////////////////
	  static const tc_interrupt_t TC_INTERRUPT =
	  {
	    .etrgs = 0,
	    .ldrbs = 0,
	    .ldras = 0,
	    .cpcs  = 1,
	    .cpbs  = 0,
	    .cpas  = 0,
	    .lovrs = 0,
	    .covfs = 0
	  };

  ////////////////////////// USART options.////////////////////////////////6
  static const usart_options_t USART_OPTIONS =
  {
    .baudrate     = 57600,
    .charlength   = 8,
    .paritytype   = USART_NO_PARITY,
    .stopbits     = USART_1_STOPBIT,
    .channelmode  = 0
  };

 
 
 /////////////////////SPI_OPTION/////////////////////
 static const spi_options_t SPI_OPTIONS =
	  {
	    .baudrate = 100000, 
	    .bits = 8,			
	    .modfdis = 1,
	    .reg  = 0,
	    .spck_delay  = 500,   
	    .spi_mode  = 1,
	    .stay_act = 1,
	    .trans_delay = 500	
	  };

 
  /////////////////////////////// Configure Osc0 in crystal mode (i.e. use of an external crystal source, with
  // frequency FOSC0) with an appropriate startup time then switch the main clock
  // source to Osc0.
 pm_switch_to_osc0(pm, FOSC0, OSC0_STARTUP);  // Switch main clock to Osc0.

  /* Setup PLL0 on Osc0, mul=9 ,no divisor, lockcount=16, ie. 12Mhz x 10 = 120MHz output */
  /* void pm_pll_setup(volatile avr32_pm_t* pm,
                  unsigned int pll,
                  unsigned int mul,
                  unsigned int div,
                  unsigned int osc,
                  unsigned int lockcount) {
 */ 
	pm_pll_setup(pm,
				 0,			// use PLL0
				 PLL_MUL,   // MUL=14 in the formula
				 PLL_DIV,   // DIV=1 in the formula
				 0,			// Sel Osc0/PLL0 or Osc1/PLL1
                 16);		// lockcount in main clock for the PLL wait lock

  /*
   This function will set a PLL option.
   *pm Base address of the Power Manager (i.e. &AVR32_PM)
   pll PLL number 0
   pll_freq Set to 1 for VCO frequency range 80-180MHz, set to 0 for VCO frequency range 160-240Mhz.
   pll_div2 Divide the PLL output frequency by 2 (this settings does not change the FVCO value)
   pll_wbwdisable 1 Disable the Wide-Bandith Mode (Wide-Bandwith mode allow a faster startup time and out-of-lock time).
				  0 to enable the Wide-Bandith Mode.
  */
  /* PLL output VCO frequency is 120MHz. We divide it by 2 with the pll_div2=1. This enable to get later main clock to 60MHz */
  pm_pll_set_option(pm, 0, 1, 1, 0);

  /* Enable PLL0 */
  /*
    void pm_pll_enable(volatile avr32_pm_t* pm,
                  unsigned int pll) {
  */
  pm_pll_enable(pm,0);

  /* Wait for PLL0 locked */
  pm_wait_for_pll0_locked(pm) ;

  /* Divide PBA clock by 2 from main clock (PBA clock = 60MHz/2 = 30MHz).
     Pheripheral Bus A clock divisor enable = 1
     Pheripheral Bus A select = 0
     Pheripheral Bus B clock divisor enable = 0
     Pheripheral Bus B select = 0
     High Speed Bus clock divisor enable = 0
     High Speed Bus select = 0
  */
  pm_cksel(pm, PBACLK_DIVEN, 0, PBBCLK_DIVEN, 0, HSBCLK_DIVEN, 0);

  // Set one wait-state (WS) for flash controller. 0 WS access is up to 30MHz for HSB/CPU clock.
  // As we want to have 60MHz on HSB/CPU clock, we need to set 1 WS on flash controller.
  flashc_set_wait_state(1);

  pm_switch_to_clock(pm, AVR32_PM_MCSEL_PLL0); /* Switch main clock to 60MHz */

 
 
  ////////////////////////666/ Assign GPIO pins./////////////////////////////6
  gpio_enable_module(USART_GPIO_MAP, sizeof(USART_GPIO_MAP) / sizeof(USART_GPIO_MAP[0]));

  gpio_enable_module(SPI_GPIO_MAP, sizeof(SPI_GPIO_MAP)/sizeof(SPI_GPIO_MAP[0]));

  gpio_enable_module(PWM_GPIO_MAP, sizeof(PWM_GPIO_MAP)/sizeof(PWM_GPIO_MAP[0]));

  gpio_enable_module(ADC_GPIO_MAP, sizeof(ADC_GPIO_MAP)/sizeof(ADC_GPIO_MAP[0]));

  /////////////////////////6/ Initialize USART in RS232 mode at 60MHz.
  usart_init_rs232(USPSR_COM_USART, &USART_OPTIONS, USPSR_PBACLK);

  // Welcome sentence.
  usart_write_line(USPSR_COM_USART, "\x1B[2J\x1B[H\r\nATMEL\r\n");
  usart_write_line(USPSR_COM_USART, "AVR32 UC3 - TC example\r\n");

  Disable_global_interrupt();

  // The INTC driver has to be used only for GNU GCC for AVR32.
#if defined (__GNUC__)
  // Initialize interrupt vectors.
  INTC_init_interrupts();

  // Register the RTC interrupt handler to the interrupt controller.
  INTC_register_interrupt(&tc_irq, USPSR_TC_IRQ, AVR32_INTC_INT0);
  
 INTC_register_interrupt(&pwm_interrupt,AVR32_PWM_IRQ, AVR32_INTC_INT0);
#endif

  Enable_global_interrupt();

	// Initialize the timer/counter.
  tc_init_waveform(tc, &WAVEFORM_OPT);         // Initialize the timer/counter waveform.

	 // Set the compare triggers.
	 // Remember TC counter is 16-bits, so counting second is not possible with fPBA = 12 MHz.
	// We configure it to count ms.
	// We want: (1/(fPBA/8)) * RC = 0.001 s, hence RC = (fPBA/8) / 1000 = 3750 to get an interrupt every 1 ms.
  tc_write_rc(tc, USPSR_TC_CHANNEL, (USPSR_PBACLK / 8)/1000); // Set RC value.

  tc_configure_interrupts(tc, USPSR_TC_CHANNEL, &TC_INTERRUPT);

  gpio_tgl_gpio_pin(USPSR_LED2_GPIO);

		// Start the timer/counter.
  tc_start(tc, USPSR_TC_CHANNEL);                    // And start the timer/counter.
//////////////////////////////////////////////////////////////////////////////////////////////////
 

  ///////////////SPI_ENABLE////////////////////////
  
  spi_initMaster(SPIO,&SPI_OPTIONS);
  
  spi_selectionMode(SPIO,0,0,0);
  
  spi_enable(SPIO);
  
  spi_setupChipReg(SPIO, &SPI_OPTIONS, FOSC0);
 
  	 unsigned short STATS0, STATS1, STATS2;
     spi_status_t err_flag0=0;
	 U16 data;
  

//////////////PWM//////////////////////////////


#define BACKLIGHT_PIN AVR32_PIN_PA07
#define BACKLIGHT_PWM_CHANNEL 0
AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].CMR.cpre=0b0000; //CLK=MCLK
AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].CMR.cpol=1; //Magas szinttel kezdodik
AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].CMR.cpd=0; //CUPDx irasa a kitoltesi tenyezot modositja
AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].CMR.calg=1;
AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].cprd=1200; //12,5khz
AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].cdty=0; //kezdetnek 0% kitoltesi tenyezo

AVR32_PWM.IER.chid0=1;


AVR32_PWM.ena=1<<BACKLIGHT_PWM_CHANNEL; //Engedelyezes
////////////////////////////////////////////////////////////////////////////////////////////////

adc_configure(ADC_BASE);
adc_enable(ADC_BASE, ADC_PIN_CURR);
adc_enable(ADC_BASE, ADC_PIN_EMF);

////////////////////////////////////////////////////////////////////////////////////////////////
U8 DIRECTION,GRAY,GRAY_2;
char dirT[16]={'2','1','0','2','0','2','2','1','1','2','2','0','2','0','1','2'};
unsigned short int dir;
unsigned short int x=10,y=0,pot=0,mov=0;

////////////////////////////////////////////////////////   
 while(TRUE)
  {
  	mov=(data-pot)&0x0FFF;
	adc_start(ADC_BASE);
	
	  
	
	if ( mov<100)
	{
		AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].cupd=(0);  
		gpio_set_gpio_pin(PWM_DIRECTION);
	}		
	else if (mov>4000)
	{
		AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].cupd=(0);
		gpio_clr_gpio_pin(PWM_DIRECTION);  
	}
	
	else
	{
		AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].cupd=(100);  
	}
	/*
	if (gpio_get_pin_value(USPSR_POT1_GPIO)==1)
	{
	AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].cupd=(100);
	}
	else
	{
	AVR32_PWM.channel[BACKLIGHT_PWM_CHANNEL].cupd=(0);		
	}
	*/
		  
	if (gpio_get_pin_value(USPSR_POT1_GPIO))
	{gpio_set_gpio_pin(USPSR_LED2_GPIO);} 
	else
	{gpio_clr_gpio_pin(USPSR_LED2_GPIO);}
	if (gpio_get_pin_value(USPSR_POT2_GPIO))
	{gpio_set_gpio_pin(USPSR_LED3_GPIO);
	 } 
	else
	{gpio_clr_gpio_pin(USPSR_LED3_GPIO);}
		
	GRAY= gpio_get_pin_value(USPSR_POT2_GPIO)<<1 |  gpio_get_pin_value(USPSR_POT1_GPIO);
	DIRECTION=((DIRECTION<<2)&0x0C)|GRAY;	
	dir=(dirT[DIRECTION])&0x0F;
	
	
	if (dir==1)
	{
		gpio_set_gpio_pin(PWM_DIRECTION);
		pot=(pot-80)&0x0FFF;	
	}
	if (dir==0)
	{
		gpio_clr_gpio_pin(PWM_DIRECTION);
	    pot=(pot+80)&0x0FFF;
	}
	
	
 spi_select(0);
  err_flag0 = spi_send(0xFF);  
  if (err_flag0) spi_report(err_flag0); 
  err_flag0 = spi_rcv(&STATS0); 
  if (err_flag0) spi_report(err_flag0); 
	
  err_flag0 = spi_send(0xFF);  
  if (err_flag0) spi_report(err_flag0); 
  err_flag0 = spi_rcv(&STATS1); 
  if (err_flag0) spi_report(err_flag0); 
    
  err_flag0 = spi_send(0xFF);  
  if (err_flag0) spi_report(err_flag0); 
  err_flag0 = spi_rcv(&STATS2); 
  if (err_flag0) spi_report(err_flag0); 
spi_unselect(0);
	
	//adc_curr_value=adc_get_value(ADC_BASE, ADC_PIN_CURR);
	
		
	data=(((STATS1 & 0x00F0) >>4)   | (STATS0 & 0x00FF)<<4 );

	    
	   // if ((print_sec) && (!(tc_tick%1000)))
	    //{

	      usart_write_line(USPSR_COM_USART, "\x1B[5;1H");
	      ptemp = print_i(temp,adc_emf_value);					
	      usart_write_line(USPSR_COM_USART, "Data: ");
	      usart_write_line(USPSR_COM_USART, ptemp);
	      usart_write_line(USPSR_COM_USART, " ");
		//print_sec=0;
		//} 
		 
}  
  
 


}

