#include "Cyclone_Device.h"         // UCD30xx Headers Include File
#include "software_interrupts.h"

#define PERIOD (40000)              // 4 Ghz high speed clock/100 KHz switching frequency = 40000.
int command_accepted;               //flag to tell us to update output

void handle_serial_in(char rx_byte)
{
    if((rx_byte == '=') || (rx_byte == '+'))
    {
      if( Dpwm0Regs.DPWMEV2.all < (PERIOD - (PERIOD >> 4)) )
      {
        Dpwm0Regs.DPWMEV2.all = Dpwm0Regs.DPWMEV2.all + (PERIOD >> 4);
      }
      command_accepted = 1;
    }
    else if((rx_byte == '-')|| (rx_byte == '_'))
    {
      if( Dpwm0Regs.DPWMEV2.all > (PERIOD >> 4) )
      {
        Dpwm0Regs.DPWMEV2.all = Dpwm0Regs.DPWMEV2.all - (PERIOD >> 4);
      }
      command_accepted = 1;
    }
}

void char_out(char data)
{
    char rx_byte;

    while(Uart1Regs.UARTTXST.bit.TX_RDY == 0)   //while the previous byte is transmitting
    {
        if(Uart1Regs.UARTRXST.bit.RX_RDY == 1)  //if there is a recieved byte ready
        {
            rx_byte = Uart1Regs.UARTRXBUF.bit.RXDAT; //clear RXRDY flag
            handle_serial_in(rx_byte);
        }
    }
    Uart1Regs.UARTTXBUF.all = data;             //put out the new byte
}

void string_out(char string[])
{
    int i = 0;

    while(string[i] != 0)
    {
        char_out(string[i]);
        i++;
    }
}

void nybble_out(char nybble)
{
    if(nybble < 10)
    {
        char_out(nybble + 0x30);
    }
    else
    {
        char_out(nybble + ('a' - 10)); //make 10 into an A
    }
}

void byte_out(char data)
{
    nybble_out(data >> 4);
    nybble_out(data & 0xf);
}

void three_nybble_out(unsigned short data)
{
    nybble_out(data >> 8);
    byte_out(data & 0xff);
}

void short_out(unsigned short data)
{
    byte_out(data >> 8);
    byte_out(data & 0xff);
}

void word_out(unsigned int data)
{
    short_out(data >> 16);
    short_out(data & 0xffff);
}

void init_uart(void)
{
    volatile unsigned char rx_byte;
    char startmsg[] = "ready";

    Uart1Regs.UARTCTRL3.bit.SW_RESET = 0;   //software reset while initializing UART
    Uart1Regs.UARTCTRL0.bit.DATA_SIZE = 7;  //8 bits
    Uart1Regs.UARTCTRL0.bit.STOP = 1;       //2 stop bits
    Uart1Regs.UARTCTRL0.bit.SYNC_MODE = 1;  //asynchronous mode

    Uart1Regs.UARTHBAUD.bit.BAUD_DIV_H = 0;
    Uart1Regs.UARTMBAUD.bit.BAUD_DIV_M = 1;
    Uart1Regs.UARTLBAUD.bit.BAUD_DIV_L = 0x97;  //1.95 Mhz/4800 baud = 407 = 0x197

    Uart1Regs.UARTRXST.bit.RX_ENA = 1 ;         //enable RX

    Uart1Regs.UARTTXST.bit.TX_ENA = 1;          //enable TX

    Uart1Regs.UARTINTST.all = 0xff;             //these two statements are supposed to clear the status bits
    Uart1Regs.UARTINTST.all = 0;

    rx_byte = Uart1Regs.UARTRXBUF.bit.RXDAT;    //clear RXRDY flag

    Uart1Regs.UARTIOCTRLTX.bit.IO_FUNC = 1;     //enable transmit pin
    Uart1Regs.UARTIOCTRLRX.bit.IO_FUNC = 1;     //enable receive pin

    Uart1Regs.UARTCTRL3.bit.CLOCK = 1;          //internal clock select;
    Uart1Regs.UARTCTRL3.bit.SW_RESET = 1;       //software reset released UART init done?

    Uart1Regs.UARTIOCTRLSCLK.bit.IO_FUNC = 0;   //disable external clock for UART.

    int i = 0;
    while(startmsg[i] > 0){
        Uart1Regs.UARTTXBUF.all = startmsg[i];  //put out a msg to get things started.
        i++;
    }
    Uart1Regs.UARTTXBUF.all = " ";
}

void init_dpwm0(void)
{

    Dpwm0Regs.DPWMCTRL0.bit.PWM_EN = 0;     //disable locally for init
    Dpwm0Regs.DPWMCTRL0.bit.CLA_EN = 0;     //default is 1 - use cla

    Dpwm0Regs.DPWMPRD.all = PERIOD;         //use .all for all values, make sure scaling matches.
    Dpwm0Regs.DPWMEV1.all = 0;              //Put event 1 at start of period
    Dpwm0Regs.DPWMEV2.all = PERIOD/4;       //1/4 of period - divide is OK because it's all constants.
    Dpwm0Regs.DPWMEV3.all = PERIOD/2;       //1/2 of period
    Dpwm0Regs.DPWMEV4.all = (PERIOD * 3)/4; //3/4 of period

    Dpwm0Regs.DPWMCTRL0.bit.PWM_EN = 1;     //enable locally
    LoopMuxRegs.GLBEN.bit.DPWM0_EN = 1;     //enable globally
}

void main()
{
    char rx_byte;

    if(Uart1Regs.UARTIOCTRLRX.bit.DATA_IN == 0) //emergency backdoor - RX1 is normally pulled up by RS-232 driver chip
    {
        clear_integrity_word();  //if it's pulled down, clear checksum (integrity word)
    }
    init_uart();
    init_dpwm0();
    string_out("Hello World\r\n");
    word_out(Dpwm0Regs.DPWMEV2.all);
    for(;;) //infinite loop - run time program will be here.
    {
        if(Uart1Regs.UARTRXST.bit.RX_RDY == 1) //if there is a recieved byte ready
        {
            rx_byte = Uart1Regs.UARTRXBUF.bit.RXDAT; //clear RXRDY flag
            handle_serial_in(rx_byte);
        }
        if(command_accepted == 1)
        {
            string_out("\r");
            word_out(Dpwm0Regs.DPWMEV2.all);
            command_accepted = 0;
        }
    }
}

//#pragma INTERRUPT(c_int00,RESET) // CCS 5.4 and up will give a compile time error for interrupt handlers not compiled in ARM mode

void c_int00(void)
{
    main();
}
