/*
 * pwm.c
 *
 *  Created on: 16 Jun 2020
 *      Author: tm
 */

#include "pwm.h"
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_gpio.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
//#include "pinout.h"




struct pwmDriver pwmSoln;
struct pwmDriver pwmPump;

void pwm_init(void)
{

    // //PG1, PG3 on MpHOx

    pwmSoln.state = 0;      // PG1,PG3 0=off, 1=on, 2=permil, 3=hiZ(future)
    pwmSoln.cnt = 0;
    pwmSoln.gpio = 0;   // variable holding state of gpio PG1
    pwmSoln.delta = 0;      // diff between old and new pwm settings
    pwmSoln.prevVal = 0;    // place to store previous value (speculative need)
    pwmSoln.period = 1000;  // period in microseconds (tbd) 1msec hardcoded in first implementation. inverse of frequency.
    pwmSoln.permil = 500;         // 0 to 999

    pwmPump.state = 0;      // PG1,PG3 0=off, 1=on, 2=permil, 3=hiZ(future)
    pwmPump.cnt = 0;
    pwmPump.gpio = 0;   // variable holding state of gpio PG1
    pwmPump.delta = 0;      // diff between old and new pwm settings
    pwmPump.prevVal = 0;    // place to store previous value (speculative need)
    pwmPump.period = 1000;  // period in microseconds (tbd) 1msec hardcoded in first implementation. inverse of frequency.
    pwmPump.permil = 500;         // 0 to 999

#ifdef INPROGRESS
#define SYSCTL_RCGCGPIO_R6      0x00000040  // GPIO Port G Run Mode Clock
                                            // Gating Control

    /* Enable Peripheral Clocks */
    SYSCTL_RCGCPWM_R |= 2;       /* enable clock to PWM0 is 1, PWM1 is 2 */
    SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R6;   /* enable clock to PORTG */
    SYSCTL_RCC_R &= ~0x00100000; /* no pre-divide for PWM clock */

    /* Enable port PF3 for PWM1 M1PWM7 */
    GPIO_PORTG_AFSEL_R = 0x08;      /* PG3 uses alternate function */
    GPIO_PORTG_PCTL_R &= ~0x00000000; /* make PG3 PWM output pin */
    GPIO_PORTG_PCTL_R |= 0x00000020;            //M1PWM1 is bit.5 of GPIO_PORTG_PCTL_R Digital Function (GPIOPCTL PMCx Bit Field Encoding)
    GPIO_PORTG_DEN_R |= 8;       /* pin digital */



    //
    // Configure the GPIO Pin Mux for PG3
    // for M1PWM1
    //
    MAP_GPIOPinConfigure(GPIO_PG3_M1PWM1);
    MAP_GPIOPinTypePWM(GPIO_PORTG_BASE, GPIO_PIN_3);
#endif
}
/*
 * pwm_stateMachine
 */
int pwmSoln_stateMachine(int pwmState)
{

    if(pwmState <= -1)
    {
        //use global state
    }
    else
    {
        pwmSoln.state = (uint32_t)pwmState;       // allow external mediation of stateMachine
    }

    switch(pwmSoln.state)
    {
        case ST_PWM_LO:
            //GPIO is clear / lo
            pwr_so1n_off();       //PG1/PG3
            pwmSoln.cnt = 0;
            break;

        case ST_PWM_HI:
            //GPIO is set / hi
            pwr_so1n_on();       //PG1/PG3
            pwmSoln.cnt = 0;
            break;

        case ST_PWM_PERMIL_LO:
            //GPIO is low and counting to toggle hi. low time is 1000 - permil
            pwmSoln.cnt++;
            if(pwmSoln.cnt > (1000 - pwmSoln.permil))
            {
                pwmSoln.state = ST_PWM_PERMIL_HI;
                pwr_so1n_on();       //PG1/PG3
                pwmSoln.cnt = 0;

            }
            break;

        case ST_PWM_PERMIL_HI:
            //GPIO is high and counting to toggle low (period is 1msec), high time is equal permil.
            pwmSoln.cnt++;
            if(pwmSoln.cnt > pwmSoln.permil)
            {
                pwmSoln.state = ST_PWM_PERMIL_LO;
                pwr_so1n_off();       //PG1/PG3
                pwmSoln.cnt = 0;

            }
            break;

        default:
            pwr_so1n_off();       //PG1/PG3
            pwmSoln.cnt = 0;
            break;
    }


    return(pwmSoln.state);
}



int pwmPump_stateMachine(int pwmState)
{




    if(pwmState <= -1)
    {
        //use global state
    }
    else
    {
        pwmPump.state = (uint32_t)pwmState;       // allow external mediation of stateMachine
    }

    switch(pwmPump.state)
    {
        case ST_PWM_LO:
            //GPIO is clear / lo
            pwr_pump_off();       //PG1/PG3
            pwmPump.cnt = 0;
            break;

        case ST_PWM_HI:
            //GPIO is set / hi
            pwr_pump_on();       //PG1/PG3
            pwmPump.cnt = 0;
            break;

        case ST_PWM_PERMIL_LO:
            //GPIO is low and counting to toggle hi. low time is 1000 - permil
            pwmPump.cnt++;
            if(pwmPump.cnt > (1000 - pwmPump.permil))
            {
                pwmPump.state = ST_PWM_PERMIL_HI;
                pwr_pump_on();       //PG1/PG3
                pwmPump.cnt = 0;

            }
            break;

        case ST_PWM_PERMIL_HI:
            //GPIO is high and counting to toggle low (period is 1msec), high time is equal permil.
            pwmPump.cnt++;
            if(pwmPump.cnt > pwmPump.permil)
            {
                pwmPump.state = ST_PWM_PERMIL_LO;
                pwr_pump_off();       //PG1/PG3
                pwmPump.cnt = 0;

            }
            break;

        default:
            break;
    }


    return(pwmPump.state);
}

//-----------------------------------------
#ifdef EXAMPLECODE
#include "driverlib/pin_map.h"
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_gpio.h"
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/pwm.h"

void delayMS(int ms) {
    SysCtlDelay( (SysCtlClockGet()/(3*1000))*ms ) ;
}

int
main(void)
{
    //Set the clock
   SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC |   SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

   //Configure PWM Clock to match system
   SysCtlPWMClockSet(SYSCTL_PWMDIV_1);

   // Enable the peripherals used by this program.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);  //The Tiva Launchpad has two modules (0 and 1). Module 1 covers the LED pins

    //Configure PF1,PF2,PF3 Pins as PWM
    GPIOPinConfigure(GPIO_PF1_M1PWM5);
    GPIOPinConfigure(GPIO_PF2_M1PWM6);
    GPIOPinConfigure(GPIO_PF3_M1PWM7);
    GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);

    //Configure PWM Options
    //PWM_GEN_2 Covers M1PWM4 and M1PWM5
    //PWM_GEN_3 Covers M1PWM6 and M1PWM7 See page 207 4/11/13 DriverLib doc
    PWMGenConfigure(PWM1_BASE, PWM_GEN_2, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC);
    PWMGenConfigure(PWM1_BASE, PWM_GEN_3, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC);

    //Set the Period (expressed in clock ticks)
    PWMGenPeriodSet(PWM1_BASE, PWM_GEN_2, 320);
    PWMGenPeriodSet(PWM1_BASE, PWM_GEN_3, 320);

    //Set PWM duty-50% (Period /2)
    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_5,100);
    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6,100);
    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_7,100);

    // Enable the PWM generator
    PWMGenEnable(PWM1_BASE, PWM_GEN_2);
    PWMGenEnable(PWM1_BASE, PWM_GEN_3);

    // Turn on the Output pins
    PWMOutputState(PWM1_BASE, PWM_OUT_5_BIT | PWM_OUT_6_BIT | PWM_OUT_7_BIT, true);

    //Fade
    bool fadeUp = true;
    unsigned long increment = 10;
    unsigned long pwmNow = 100;
    while(1)
    {
        delayMS(20);
        if (fadeUp) {
            pwmNow += increment;
            if (pwmNow >= 320) { fadeUp = false; }
        }
        else {
            pwmNow -= increment;
            if (pwmNow <= 10) { fadeUp = true; }
        }
        PWMPulseWidthSet(PWM1_BASE, PWM_OUT_5,pwmNow);
        PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6,pwmNow);
        PWMPulseWidthSet(PWM1_BASE, PWM_OUT_7,pwmNow);
    }

}
#endif









//----------------------------------------

#ifdef NOCODE



SYSCTL->RCGCPWM |= (1<<0); /*enable clock source to PWM0 module */

//PG1, PG3 on MpHOx

//What about Pump PD1 or PD2 or PD3 not sure

#include <stdint.h>
#include "inc/tm4c123gh6pm.h"

void delayMs(int n);

int main(void)
{
    int x = 15999;

    /* Enable Peripheral Clocks */
    SYSCTL_RCGCPWM_R |= 2;       /* enable clock to PWM1 */
    SYSCTL_RCGCGPIO_R |= 0x20;   /* enable clock to PORTF */
    SYSCTL_RCC_R &= ~0x00100000; /* no pre-divide for PWM clock */

    /* Enable port PF3 for PWM1 M1PWM7 */
    GPIO_PORTF_AFSEL_R = 8;      /* PF3 uses alternate function */
    GPIO_PORTF_PCTL_R &= ~0x0000F000; /* make PF3 PWM output pin */
    GPIO_PORTF_PCTL_R |= 0x00005000;
    GPIO_PORTF_DEN_R |= 8;       /* pin digital */

    PWM1_3_CTL_R = 0;            /* stop counter */
    PWM1_3_GENB_R = 0x0000008C;  /* M1PWM7 output set when reload, */
                                 /* clear when match PWMCMPA */
    PWM1_3_LOAD_R = 16000;       /* set load value for 1kHz (16MHz/16000) */
    PWM1_3_CMPA_R = 15999;       /* set duty cycle to min */
    PWM1_3_CTL_R = 1;            /* start timer */
    PWM1_ENABLE_R = 0x80;        /* start PWM1 ch7 */

    for(;;) {
        x = x - 100;

        if (x <= 0)
            x = 16000;

        PWM1_3_CMPA_R = x;

        delayMs(20);
    }
}


/* delay n milliseconds (16 MHz CPU clock) */
void delayMs(int n)
{
    int i, j;

    for(i = 0 ; i < n; i++)
        for(j = 0; j < 3180; j++)
            {}  /* do nothing for 1 ms */
}
#endif
