/*
 * Copyright (c) 2021, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  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.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS 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.
 */



#include <string.h>
#include <stdio.h>
#include <ti/driverlib/dl_adc12.h>
#include <ti/driverlib/dl_gpio.h>
#include <ti/driverlib/dl_timerg.h>
#include <ti/driverlib/dl_uart_main.h>
#include <ti_msp_dl_config.h>


 
void uart_log(char* str, const uint8_t len)
{
    for(uint8_t i=0; i< len; ++i)
    {
        DL_UART_Main_transmitDataBlocking(UART_0_INST,str[i]);
    }
}

void print_value_u32(const uint8_t id, const uint32_t v)
{
    const char formatValue[] = "value %i: %i\r\n";
    char output[50] = {0};

    sprintf(output,formatValue,id,v);
    uart_log(output,strlen(output));
}

void GROUP1_IRQHandler()
{

}

void UART_0_INST_IRQHandler()
{


}

void TIMER_WAKE_UP_INST_IRQHandler()
{

}


int main(void)
{
    volatile uint16_t lAiVbatMon =   0u;
    volatile uint32_t lVbat =        0u;
    
    volatile DL_SYSCTL_RESET_CAUSE resetCause;

    SYSCFG_DL_init();  

    resetCause = DL_SYSCTL_getResetCause();

    if(resetCause == DL_SYSCTL_RESET_CAUSE_BOR_WAKE_FROM_SHUTDOWN)
    {
        
        SYSCFG_DL_GPIO_init();
        DL_SYSCTL_releaseShutdownIO();
        DL_GPIO_disableWakeUp(GPIO_GRP_0_DI_SW_BWD_IOMUX);
        DL_GPIO_disableWakeUp(GPIO_GRP_0_DI_ST_MOTOR_IOMUX);
        DL_GPIO_disableWakeUp(GPIO_GRP_0_DO_MOTOR_DIR_IOMUX);
        DL_GPIO_disableWakeUp(GPIO_GRP_0_DO_MOTOR_EN_IOMUX);
        DL_GPIO_disableWakeUp(GPIO_GRP_0_VBAT_MON_EN_IOMUX);
        DL_GPIO_disableWakeUp(GPIO_GRP_0_VBAT_SW_EN_IOMUX);
        DL_GPIO_disableWakeUp(GPIO_UART_0_IOMUX_RX);
        DL_GPIO_disableWakeUp(GPIO_UART_0_IOMUX_TX);
        DL_GPIO_disableWakeUp(GPIO_DO_PWM_MOTOR_C0_IOMUX);

    }  

    // DL_GPIO_setPins(GPIO_GRP_0_PORT,GPIO_GRP_0_VBAT_SW_EN_PIN);
    

    /* turn off peripherals before going to standby0 mode */
    DL_ADC12_disablePower(ADC12_0_INST);
    DL_UART_Main_disablePower(UART_0_INST);
    DL_TimerG_disablePower(DO_PWM_MOTOR_INST);
    DL_TimerG_disablePower(TIMER_WAIT_INST);
    DL_SYSCTL_setPowerPolicySHUTDOWN();

    

    // NVIC_EnableIRQ(GPIO_GRP_0_INT_IRQN);
    // NVIC_EnableIRQ(UART_0_INST_INT_IRQN);
    // NVIC_EnableIRQ(TIMER_WAKE_UP_INST_INT_IRQN);

    // DL_GPIO_enableFastWakePins(GPIO_GRP_0_PORT,GPIO_GRP_0_DI_SW_BWD_PIN);

    // char startupstr[100] = {0};
    // char name[] = "BMW Emergency Box";
    // char version[] = "v0.1";
    // sprintf(startupstr,"%s - %s (%X) (%X) (%X) - (reset: %X)\r\n",name,version,FACTORYREGION->DEVICEID,FACTORYREGION->USERID,FACTORYREGION->TRACEID, resetCause);
    // uart_log(startupstr,strlen(startupstr));   


    

    DL_GPIO_setPins(GPIO_GRP_0_PORT,GPIO_GRP_0_DO_MOTOR_DIR_PIN);

    static volatile uint32_t lIsSwitchActivated = 0u;
    lIsSwitchActivated = DL_GPIO_readPins(GPIO_GRP_0_PORT,GPIO_GRP_0_DI_SW_BWD_PIN);

    /* check on input switch */
    if((lIsSwitchActivated & GPIO_GRP_0_DI_SW_BWD_PIN) != GPIO_GRP_0_DI_SW_BWD_PIN)
    {
        /* switch has been activated! */

        /* power on ADC */
        DL_ADC12_enablePower(ADC12_0_INST);
        DL_UART_Main_enablePower(UART_0_INST);

        /* enable ADC conversion */
        DL_ADC12_enableConversions(ADC12_0_INST);

        /* enable Vbat monitor */
        DL_GPIO_setPins(GPIO_GRP_0_PORT,GPIO_GRP_0_VBAT_MON_EN_PIN);

        /* wait 0.5 ms, to wait load of capacitance on input pin to be read by ADC*/
        DL_Common_delayCycles(2000u);

        /* start adc sampling */
        DL_ADC12_startConversion(ADC12_0_INST);

        /* wait 50 cycles sampling */
        DL_Common_delayCycles(50u);

        /* stop adc sampling and start conversion */
        DL_ADC12_stopConversion(ADC12_0_INST);

        /* wait end of conversion */
        while(DL_ADC12_isConversionsEnabled(ADC12_0_INST) == true);

        /* read adc values */
        lAiVbatMon = DL_ADC12_getMemResult(ADC12_0_INST,ADC12_0_ADCMEM_AI_VBAT_MON);
        // print_value_u32(0u,lAiVbatMon);

        /* turn off ADC and UART */
        DL_ADC12_disablePower(ADC12_0_INST);
        DL_UART_disablePower(UART_0_INST);

        /* disable Vbat monitor */
        DL_GPIO_clearPins(GPIO_GRP_0_PORT,GPIO_GRP_0_VBAT_MON_EN_PIN);

        /* calc Vbat (mV) */
        /* 
            Vbat = (Vcc/2^ADCResolution) * ADCrawValue * VoltageDividerFactor
            Vcc = 3.3 V (3300 mV)
            ADCResolution = 12 bits
            VoltageDividerFactor = 8
        */
        lVbat = (3300u * lAiVbatMon * 8u) / (4096u);
        // print_value_u32(1u,lVbat);

        /* check against threshold: if Vbat is above 9V, activate motor */
        if(lVbat > 9000u)
        {
            /* motor must be activated! */

            /* enable PWM timer */
            DL_TimerG_enablePower(DO_PWM_MOTOR_INST);

            /* enable wait timer */
            DL_TimerG_enablePower(TIMER_WAIT_INST);

            /* enable motor driver */
            DL_GPIO_setPins(GPIO_GRP_0_PORT,GPIO_GRP_0_DO_MOTOR_EN_PIN);

            /* drive motor with 100% PWM */
            DL_TimerG_setCaptureCompareValue(DO_PWM_MOTOR_INST,150,GPIO_DO_PWM_MOTOR_C0_IDX);
            DL_TimerG_startCounter(DO_PWM_MOTOR_INST);

            /* wait 300 ms before stoppin the motor */
            DL_TimerG_startCounter(TIMER_WAIT_INST);
            while(DL_TimerG_isRunning(TIMER_WAIT_INST) == true);

            /* stop motor */
            DL_TimerG_stopCounter(DO_PWM_MOTOR_INST);

            /* disable motor driver */
            DL_GPIO_clearPins(GPIO_GRP_0_PORT,GPIO_GRP_0_DO_MOTOR_EN_PIN);

            /* disable PWM timer*/
            DL_TimerG_disablePower(DO_PWM_MOTOR_INST);

            /* disable wait timer */
            DL_TimerG_disablePower(TIMER_WAIT_INST);


        } /*  end of if(Vbat > 9000u) */
    } /* end of if((lIsSwitchActivated & GPIO_GRP_0_DI_SW_BWD_PIN) == 0u) */

    DL_GPIO_initDigitalInputFeatures(GPIO_GRP_0_DI_SW_BWD_IOMUX,DL_GPIO_INVERSION_DISABLE,DL_GPIO_RESISTOR_NONE,DL_GPIO_HYSTERESIS_DISABLE,DL_GPIO_WAKEUP_ON_1);
    DL_Common_delayCycles(4000u);
    DL_GPIO_clearPins(GPIO_GRP_0_PORT,GPIO_GRP_0_DO_MOTOR_DIR_PIN);
    

    while(1)
    {
        __WFI();
    }
}
