
/*----- system files -------------------------------------------------*/

#include <msp430f5418a.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include "driverlib.h"


static long unsigned int mclk_frequency;
static long unsigned int aclk_frequency;
static long unsigned int smclk_frequency;

#define P7XIN 0x01

void InitialiseClocks( void )
{
    // Ensure input is ON
    P7SEL |= P7XIN;

    // 20MHz crystal attached to XT1
    UCS_setExternalClockSource(20e6,0);

    //Turns on XT1
    UCS_turnOnHFXT1(UCS_XT1_DRIVE_2);

    //Turns off XT2
    UCS_turnOffXT2();

    // Enable clock requests for the following
    UCS_enableClockRequest(UCS_SMCLK);
    UCS_enableClockRequest(UCS_MCLK);
    UCS_disableClockRequest(UCS_ACLK);

    //Set ACLK = XT1
    UCS_initClockSignal(
            UCS_ACLK,
            UCS_XT1CLK_SELECT,
            UCS_CLOCK_DIVIDER_1
            );

    //Set SMCLK = REFO / 16
    UCS_initClockSignal(
            UCS_SMCLK,
            UCS_REFOCLK_SELECT,
            UCS_CLOCK_DIVIDER_16
            );

    //Set ACLK output pin div 5
    UCSCTL5 |= DIVPA__4;

    // Slow 5MHz please
    UCS_initClockSignal(
            UCS_MCLK,
            UCS_XT1CLK_SELECT,
            UCS_CLOCK_DIVIDER_4
            );

    // Disable the DCO faults
    SFR_disableInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT);

    // Record the MCLK frequency for shiz n giggles
    mclk_frequency = UCS_getMCLK();
    aclk_frequency = UCS_getACLK();
    smclk_frequency = UCS_getSMCLK();
}

void InitialisePMM( void )
{
    // Set Vcore setting required for 5MHz operation
    // But please operate much faster so we have no issue
    // at running on top speed
    PMM_disableSvmLInterrupt();
    PMM_disableSvmHInterrupt();
    PMM_setVCore(PMM_CORE_LEVEL_0);
    PMM_enableSvmLInterrupt();
    PMM_enableSvmHInterrupt();
}


void InitialiseMode ( void )
{
    /* Eratta PMM17
     *   Vcore exceed maximum limit of 2.0V
     */
    *(unsigned int*)(0x0110)=0x9602;
    *(unsigned int*)(0x0112)|=0x0800;

    /*
     * Disable BSL protection anyway
     */
    SYSBSLC = 0x0000;

    /* Setup the new power mode for going UP in power mode. */
    InitialisePMM();
    /* Setup all system clocks for desired power mode */
    InitialiseClocks();

    /* Enable the FLASH and Memory access interrupts
     */
    SFR_clearInterrupt(SFR_VACANT_MEMORY_ACCESS_INTERRUPT |
            SFR_FLASH_CONTROLLER_ACCESS_VIOLATION_INTERRUPT);
    SFR_enableInterrupt(SFR_VACANT_MEMORY_ACCESS_INTERRUPT |
            SFR_FLASH_CONTROLLER_ACCESS_VIOLATION_INTERRUPT);
}

static char ItsTimeToDie[64];

int main(void) {

    InitialiseMode();

    WDT_A_hold(WDT_A_BASE);

    /* This function call WILL kill the application with a vacant memory interrupt call when built with
     * PROOF, otherwise not
     */
    snprintf(ItsTimeToDie, sizeof(ItsTimeToDie), "mclk=%ld smclk=%ld, aclk=%ld\n", mclk_frequency,smclk_frequency, aclk_frequency );

    printf(ItsTimeToDie);

    return (0);
}

#pragma vector=PORT2_VECTOR
__interrupt void port2_interrupt( void )
{
    while (1);
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void timer0_a0_interrupt( void )
{
    while (1);
}

#pragma vector= unused_interrupts
__interrupt void TRAPINT_ISR(void)
{
    while (1);
}

#pragma vector = WDT_VECTOR
__interrupt void WDT_ISR(void)
{
    while (1);
}

#pragma vector=UNMI_VECTOR
__interrupt void UNMI_ISR(void)
{
    switch (__even_in_range(SYSUNIV, 0x08))  // all need to trace
    {
    case SYSUNIV_NONE:
        break;
    case SYSUNIV_NMIIFG:
        break;
    case SYSUNIV_OFIFG:
        if (UCS_clearAllOscFlagsWithTimeout(10) != 0) {
            while (1);
        }

        break;

    case SYSUNIV_ACCVIFG:
        SFR_clearInterrupt(SFR_FLASH_CONTROLLER_ACCESS_VIOLATION_INTERRUPT);

        while (1);

    default:
        break;
    }
}

#pragma vector=SYSNMI_VECTOR
__interrupt void SYSNMI_ISR(void) {
    switch (__even_in_range(SYSSNIV, 0x12)) {
    case SYSSNIV_NONE:
        break;
    case SYSSNIV_SVMLIFG:
        break;
    case SYSSNIV_SVMHIFG:
        break;
    case SYSSNIV_DLYLIFG:
        break;
    case SYSSNIV_DLYHIFG:
        break;
    case SYSSNIV_VMAIFG:
        SFR_clearInterrupt(SFR_VACANT_MEMORY_ACCESS_INTERRUPT);
        /* We have a memory problem! */
        while (1);

    case SYSSNIV_JMBINIFG:
        break;
    case SYSSNIV_JMBOUTIFG:
        break;
    case SYSSNIV_VLRLIFG:
        break;
    case SYSSNIV_VLRHIFG:
        break;
    default:
        break;
    }
}

#pragma vector=USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void) {
    while (1);
}

#pragma vector=ADC12_VECTOR
__interrupt void ADC12_ISR(void) {
    while (1);
}

#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR(void) {
    while (1);
}

#pragma vector=DMA_VECTOR
__interrupt void DMA_ISR(void) {
    while (1);
}

#pragma vector=USCI_B1_VECTOR
__interrupt void USCI_B1_ISR(void) {
    while (1);
}

#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void) {
    while (1);
}

#define STACK_FILL_PATTERN  0xBEEF  ///< Stack fill pattern for checking depth
#define HEAP_FILL_PATTERN   0xCAFE  ///< Heap fill pattern for checking usage
#define FREE_FILL_PATTERN   0xDEAD

extern int _stack;              // Lowest address of stack
extern int _sys_memory;         // Start of heap
extern void * __SYSMEM_SIZE;    // Size of heap
extern void * __STACK_END;      // End of stack

/***************************************************************************//**
 * @brief Perform system pre-initialization
 *
 * Fills the stack and the heap with known patters so that the utilization of
 * each area can be monitored at runtime to detect overflows.  Uses registers
 * because we don't want to use more stack space than necessary.
 *
 * @return int  Always returns 1
 *
 ******************************************************************************/
int _system_pre_init(void)
{
    // Get lowest stack address
    register uint16_t * pMem = (uint16_t *)(&_stack);

    // Don't overwrite return address of caller, so subtract two words from end of stack
    register uint16_t * pEnd = (uint16_t *)(&__STACK_END - 10);

    // Fill stack with known pattern to check usage during runtime
    while (pMem < pEnd)
    {
        *pMem++ = STACK_FILL_PATTERN;
    }

    return 1;
}
