/*
 *  Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ 
 *  
 *  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.
 *  
 */
 
/*
 *  ======== HwiP_nortos.c ========
 *  TODO is this the correct license?
 */

#include <stdio.h>
#include <stdlib.h>
#include <ti/drivers/ports/HwiP.h>

/* Driver lib includes */
#include <inc/hw_types.h>
#include <driverlib/interrupt.h>
#include <driverlib/rom.h>
#include <driverlib/rom_map.h>

#define MAX_INTERRUPTS 256

/*
 *  ======== HwiP_DispatchEntry ========
 */
typedef struct HwiP_DispatchEntry {
    HwiP_Fxn entry;
    uintptr_t arg;
} HwiP_DispatchEntry;

HwiP_DispatchEntry HwiP_dispatchTable[MAX_INTERRUPTS] = {{(HwiP_Fxn)0, 0}};

/*
 *  ======== HwiP_disable ========
 */
uintptr_t HwiP_disable(void)
{
    IntMasterDisable();
    return (0);
}

/*
 *  ======== HwiP_restore ========
 */
void HwiP_restore(uintptr_t key)
{
    IntMasterEnable();
}

#ifndef xdc_target__isaCompatible_28

typedef struct Hwi_NVIC {
    uint32_t RES_00;
    uint32_t ICTR;
    uint32_t RES_08;
    uint32_t RES_0C;
    uint32_t STCSR;
    uint32_t STRVR;
    uint32_t STCVR;
    uint32_t STCALIB;
    uint32_t RES_20[56];
    uint32_t ISER[8];
    uint32_t RES_120[24];
    uint32_t ICER[8];
    uint32_t RES_1A0[24];
    uint32_t ISPR[8];
    uint32_t RES_220[24];
    uint32_t ICPR[8];
    uint32_t RES_2A0[24];
    uint32_t IABR[8];
    uint32_t RES_320[56];
    uint8_t IPR[240];
    uint32_t RES_4F0[516];
    uint32_t CPUIDBR;
    uint32_t ICSR;
    uint32_t VTOR;
    uint32_t AIRCR;
    uint32_t SCR;
    uint32_t CCR;
    uint8_t SHPR[12];
    uint32_t SHCSR;
    uint8_t MMFSR;
    uint8_t BFSR;
    uint16_t UFSR;
    uint32_t HFSR;
    uint32_t DFSR;
    uint32_t MMAR;
    uint32_t BFAR;
    uint32_t AFSR;
    uint32_t PFR0;
    uint32_t PFR1;
    uint32_t DFR0;
    uint32_t AFR0;
    uint32_t MMFR0;
    uint32_t MMFR1;
    uint32_t MMFR2;
    uint32_t MMFR3;
    uint32_t ISAR0;
    uint32_t ISAR1;
    uint32_t ISAR2;
    uint32_t ISAR3;
    uint32_t ISAR4;
    uint32_t RES_D74[5];
    uint32_t CPACR;
    uint32_t RES_D8C[93];
    uint32_t STI;
    uint32_t RES_F04[12];
    uint32_t FPCCR;
    uint32_t FPCAR;
    uint32_t FPDSCR;
    uint32_t MVFR0;
    uint32_t MVFR1;
    uint32_t RES_F48[34];
    uint32_t PID4;
    uint32_t PID5;
    uint32_t PID6;
    uint32_t PID7;
    uint32_t PID0;
    uint32_t PID1;
    uint32_t PID2;
    uint32_t PID3;
    uint32_t CID0;
    uint32_t CID1;
    uint32_t CID2;
    uint32_t CID3;
} Hwi_NVIC;

/*
 *  ======== HwiP_clearInterrupt ========
 */
void HwiP_clearInterrupt(int interruptNum)
{
    // TODO: Should driverlib functions be prefixed with MAP_?
    IntPendClear((unsigned long)interruptNum);
}

/*
 *  ======== HwiP_delete ========
 */
HwiP_Status HwiP_delete(HwiP_Handle handle)
{
    IntDisable((int)handle);
    IntUnregister((int)handle);

    return (HwiP_OK);
}

/*
 *  ======== HwiP_disableInterrupt ========
 */
void HwiP_disableInterrupt(int interruptNum)
{
    IntDisable(interruptNum);
}

uint32_t intNum;
HwiP_DispatchEntry hwi;

/*
 *  ======== HwiP_dispatch ========
 */
void HwiP_dispatch(void)
{
    
    Hwi_NVIC *Hwi_nvic = (Hwi_NVIC *)0xE000E000;
    //HwiP_DispatchEntry hwi;

    /* Determine which interrupt has fired */
    intNum = (Hwi_nvic->ICSR & 0x000000ff);
    hwi = HwiP_dispatchTable[intNum];
    if (hwi.entry) {
        (hwi.entry)(hwi.arg);
    }
}

/*
 *  ======== HwiP_enableInterrupt ========
 */
void HwiP_enableInterrupt(int interruptNum)
{
    IntEnable(interruptNum);
}

/*
 *  ======== HwiP_create ========
 */
HwiP_Handle HwiP_create(int interruptNum,
                        HwiP_Fxn hwiFxn,
                        HwiP_Params *params)
{
    HwiP_Params defaultParams;

    if (params == NULL) {
        params = &defaultParams;
        HwiP_Params_init(&defaultParams);
    }

    HwiP_dispatchTable[interruptNum].entry = hwiFxn;
    HwiP_dispatchTable[interruptNum].arg = params->arg;

    // TODO: Should driverlib functions be prefixed with MAP_?
    IntRegister(interruptNum, (void(*)(void))HwiP_dispatch);
    IntPrioritySet(interruptNum, params->priority);
    IntEnable(interruptNum);

    return ((HwiP_Handle)interruptNum);
}

void HwiP_Params_init(HwiP_Params *params)
{
    if(params != NULL)
    {
        params->name = NULL;
        params->arg = NULL;
        params->priority = INT_PRIORITY_LVL_1;
    }
}
#endif
