/*******************************************************************************
  Main Source File

  Company:
    Microchip Technology Inc.

  File Name:
    main.c

  Summary:
    This file contains the "main" function for a project.

  Description:
    This file contains the "main" function for a project.  The
    "main" function calls the "SYS_Initialize" function to initialize the state
    machines of all modules in the system
 *******************************************************************************/

// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************

#include <stddef.h>                     // Defines NULL
#include <stdbool.h>                    // Defines true
#include <stdlib.h>                     // Defines EXIT_FAILURE
#include "definitions.h"                // SYS function prototypes
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

uint32_t i = 0;
uint8_t USARTRTxBuffer[100];
uint8_t USART5_ReceiveData[1];
volatile uint8_t USART5_IsReceived = 0;
volatile uint8_t USART5_IsTransmitted = 1;

#define SYS_CONSOLE_PRINT_BUFFER_SIZE	200
static char consolePrintBuffer[SYS_CONSOLE_PRINT_BUFFER_SIZE];
volatile uint8_t TC3_HasExpired = 0;
volatile uint8_t TC4_HasExpired = 0;

uint16_t ADC_Result[2];
volatile uint8_t ADC_IsCompleted = 0;
volatile int8_t  ADC_ChannelIdx = 0;

// TODO 16.02
uint8_t Duty = 50;
int8_t DutyDistance = 2;

void myprintf(const char *format, ...)
{
    size_t len = 0;
    va_list args = {0};
    va_start(args, format);
    len = vsnprintf(consolePrintBuffer, SYS_CONSOLE_PRINT_BUFFER_SIZE, format, args);
    va_end(args);

    if ((len > 0) && (len < SYS_CONSOLE_PRINT_BUFFER_SIZE))
    {
        consolePrintBuffer[len] = '\0';
        SERCOM5_USART_Write(consolePrintBuffer, len);
        while (SERCOM5_USART_WriteIsBusy());
    }
}

void USART5_Transmit( uintptr_t context )
{
    USART5_IsTransmitted = 1;
} 

void USART5_Receive( uintptr_t context )
{
    USART5_IsReceived = 1;
}

void TC3_TimerExpired(TC_TIMER_STATUS status, uintptr_t context) 
{
    if( status & TC_INTFLAG_OVF_Msk)
    {
        TC3_HasExpired = 1;
    }
}

void TC4_TimerExpired(TC_TIMER_STATUS status, uintptr_t context) 
{
    if( status & TC_INTFLAG_OVF_Msk)
    {
        TC4_HasExpired = 1;
    }
}

void ADC_Complete( ADC_STATUS status, uintptr_t context )
{
    if( status & ADC_INTFLAG_RESRDY_Msk )
    {
        ADC_Result[ADC_ChannelIdx] = ADC_ConversionResultGet();
        ADC_ChannelIdx = ( ADC_ChannelIdx + 1 ) % 2;
        if( ADC_ChannelIdx == 0 )
        {
            ADC_IsCompleted = 1;
        }
    }
}

// *****************************************************************************
// *****************************************************************************
// Section: Main Entry Point
// *****************************************************************************
// *****************************************************************************

int main ( void )
{
    /* Initialize all modules */
    SYS_Initialize ( NULL );
    
    TC3_TimerCallbackRegister( TC3_TimerExpired, (uintptr_t )NULL );
    TC3_TimerStart();
    TC4_TimerCallbackRegister( TC4_TimerExpired, (uintptr_t )NULL );
    TC4_TimerStart();
    
    SERCOM5_USART_ReadCallbackRegister( USART5_Receive, (uintptr_t )NULL );
    SERCOM5_USART_WriteCallbackRegister( USART5_Transmit, (uintptr_t )NULL );
    SERCOM5_USART_Read( USART5_ReceiveData, 1 );
    
    ADC_CallbackRegister( ADC_Complete, (uintptr_t )NULL );
    ADC_Enable();
    
    myprintf("\033[2J");
    myprintf("\033[?25l");
    
    TCC2_PWMStart();

    while ( true )
    {
        /* Maintain state machines of all polled MPLAB Harmony modules. */
        SYS_Tasks ( );
        
        if (TC3_HasExpired)
        {
            TC3_HasExpired = 0;
            LED1_Toggle();
            myprintf( "\033[1;1HHello World!" );
        }
        
        if (TC4_HasExpired)
        {
            TC4_HasExpired = 0;
            LED2_Toggle();
            ADC_ConversionStart();
            
            // TODO 16.03
            Duty += DutyDistance;
            if (Duty >= 100 || Duty <= 0)
                DutyDistance = -DutyDistance;
            
            TCC2_PWM16bitDutySet( 1, ((uint32_t)Duty * (TCC2_PWM16bitPeriodGet() + 1)) / 100 );
        }
        
        if( USART5_IsReceived )
        {
            USART5_IsReceived = 0;
            myprintf("\033[6;1HReceived Data : %1c", USART5_ReceiveData[0] );
            SERCOM5_USART_Read( USART5_ReceiveData, 1 );
        }
        
        if( ADC_IsCompleted )
        {
            ADC_IsCompleted = 0;

            myprintf( "\033[2;1HVR1 Value : %4d", ADC_Result[0] );
            myprintf( "\033[3;1HTemperature Value : %4d", ADC_Result[1] );
            
            // TODO 16.01
            // TCC2_PWM16bitDutySet( 1, (uint32_t)ADC_Result[0] * (TCC2_PWM16bitPeriodGet() + 1) / 4095 );
        }
    }

    /* Execution should not come here during normal operation */

    return ( EXIT_FAILURE );
}


/*******************************************************************************
 End of File
*/

