%%{
/*
 * Copyright (c) 2018-2019, Texas Instruments Incorporated - http://www.ti.com
 * 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.
 *
 */

/*
 *  ======== Timer.Board.c.xdt ========
 */

    let TIMER = args[0]; /* passed by /ti/drivers/templates/Board.c.xdt */
    let content = args[1];

    let Common = system.getScript("/ti/driverlib/Common.js");

    /* shorthand names for some common references in template below */
    let instances = TIMER.$instances;
    if (instances.length == 0) return;


    switch(content){
        case "Call":
            printCall();
            break;
        case "Reset":
            printReset();
            break;
        case "Power":
            printPower();
            break;
        case "GPIO":
            printGPIO();
            break;
        case "Function":
            printFunction();
            break;
        case "RetentionDeclare":
            printRetentionDeclare();
            break;
        case "RetentionSave":
            printRetentionSave();
            break;
        case "RetentionRestore":
            printRetentionRestore();
            break;
        case "RetentionRdy":
            printRetentionRdy();
            break;
        default:
            /* do nothing */
            return;
            break;
    }
%%}
%
% function printCall(){
%   for (let i in instances) {
%       let inst = instances[i];
    SYSCFG_DL_`inst.$name`_init();
%   }
% }
%
% /* Retention Configuration Code */
% function printRetentionDeclare(){
`Common.getRetentionDeclareC(instances,"Timer")`
% }
% function printRetentionRdy(){
`Common.getRetentionRdyC(instances,"Timer")`
% }
% function printRetentionSave(){
`Common.getRetentionSaveC(instances,"Timer")`
% }
% function printRetentionRestore(){
`Common.getRetentionRestoreC(instances,"Timer")`
% }
%
% function printReset(){
% for (let i in instances) {
%       let inst = instances[i];
%       let flavor = inst.peripheral.$solution.peripheralName;
%       /* one way to get a context category, such as TIMERA */
%       let flavorCat = "Timer"+(flavor.replace(/[0-9]/g, '')).slice(3);
    DL_`flavorCat`_reset(`inst.$name`_INST);
%   }
% }
% function printPower(){
% for (let i in instances) {
%       let inst = instances[i];
%       let flavor = inst.peripheral.$solution.peripheralName;
%       let flavorCat = "Timer"+(flavor.replace(/[0-9]/g, '')).slice(3);
%       /* another possibility depending on the driver */
    DL_`flavorCat`_enablePower(`inst.$name`_INST);
%   }
% }
%
% function printGPIO(){
%   for (let i in instances) {
%       let inst = instances[i];
%       let flavor = inst.peripheral.$solution.peripheralName;
%       for(let cc in inst.ccIndex){
%       /* all of these are defined in the header */
%           let gpioStr = "GPIO_"+inst.$name+"_C"+cc;
    DL_GPIO_initPeripheralOutputFunction(`gpioStr`_IOMUX,`gpioStr`_IOMUX_FUNC);
    DL_GPIO_enableOutput(`gpioStr`_PORT, `gpioStr`_PIN);
%       } // For i in inst.
%       if(flavor.match("TIMA.")){
%               if ((inst.faultHandlerEn && inst.faultSource.includes("0"))){
%                   let gpioStr = "GPIO_"+inst.$name;
    DL_GPIO_initPeripheralInputFunction(`gpioStr`_IOMUX_FAULT_0,`gpioStr`_IOMUX_FAULT_0_FUNC);
%               } // if typeof
%               if ((inst.faultHandlerEn && inst.faultSource.includes("1"))){
%                   let gpioStr = "GPIO_"+inst.$name;
    DL_GPIO_initPeripheralInputFunction(`gpioStr`_IOMUX_FAULT_1,`gpioStr`_IOMUX_FAULT_1_FUNC);
%               } // if typeof
%               if ((inst.faultHandlerEn && inst.faultSource.includes("2"))){
%                   let gpioStr = "GPIO_"+inst.$name;
    DL_GPIO_initPeripheralInputFunction(`gpioStr`_IOMUX_FAULT_2,`gpioStr`_IOMUX_FAULT_2_FUNC);
%               } // if typeof
%        } // if flavor.match("TIMA.")
%   }// if instances
%}
%
% /* Main Function */
% function printFunction(){
%   let crossTriggerMainEn = false;
%   for (let i in instances) {
%       let inst = instances[i];
%       let flavor = inst.peripheral.$solution.peripheralName;
%       let flavorCat = "Timer"+(flavor.replace(/[0-9]/g, '')).slice(3);
%       /* keep track if Cross Trigger is enabled as main for later code generation */
%       if(inst.crossTriggerEn && (inst.crossTriggerAuthority == "Main")){
%           crossTriggerMainEn = true;
%       }
%

/*
 * Timer clock configuration to be sourced by `inst.timerClkSrc` / `inst.clockDivider` (`inst.timerClockSourceCalculated` Hz)
 * timerClkFreq = (timerClkSrc / (timerClkDivRatio * (timerClkPrescale + 1)))
 *   `inst.timerClockFreqNum` Hz = `inst.timerClockSourceCalculated` Hz / (`inst.timerClkDiv` * (`inst.timerClkPrescale-1` + 1))
 */
static const DL_`flavorCat`_ClockConfig g`inst.$name`ClockConfig = {
    .clockSel    = DL_TIMER_CLOCK_`inst.timerClkSrc`,
    .divideRatio = DL_TIMER_CLOCK_DIVIDE_`inst.timerClkDiv`,
    .prescale    = `inst.timerClkPrescale - 1`U,
};

/*
 * Timer load value (where the counter starts from) is calculated as (timerPeriod * timerClockFreq) - 1
 * `inst.$name`_INST_LOAD_VALUE = (`inst.timerPeriod` * `inst.timerClockFreqNum` Hz) - 1
 */
static const DL_`flavorCat`_TimerConfig g`inst.$name`TimerConfig = {
%    let timerCommence = inst.timerStartTimer?"START":"STOP";
    .period     = `inst.$name`_INST_LOAD_VALUE,
    .timerMode  = DL_TIMER_TIMER_MODE_`inst.timerMode`,
    .startTimer = DL_TIMER_`timerCommence`,
};

SYSCONFIG_WEAK void SYSCFG_DL_`inst.$name`_init(void) {

    DL_`flavorCat`_setClockConfig(`inst.$name`_INST,
        (DL_`flavorCat`_ClockConfig *) &g`inst.$name`ClockConfig);

    DL_`flavorCat`_initTimerMode(`inst.$name`_INST,
        (DL_`flavorCat`_TimerConfig *) &g`inst.$name`TimerConfig);
%
%    /* Interrupt generation */
%    let interArgs = "";
%    for (let inter of inst.interrupts) {
%        interArgs += "DL_TIMER"+(flavor.replace(/[0-9]/g,'')).slice(3)+"_INTERRUPT_"+inter+"_EVENT |\n\t\t";
%    }
%    if(inst.interrupts.length > 0){
%        interArgs = interArgs.slice(0,-5); // remove last OR and whitespace
%        let interFct = "DL_"+flavorCat+"_enableInterrupt("+inst.$name+"_INST , "+interArgs+");";
%        if(inst.interruptPriority !== "DEFAULT"){
%            let irqnStr = inst.$name + "_INST_INT_IRQN";
%            interFct += "\n\tNVIC_SetPriority(" + irqnStr + ", " +inst.interruptPriority + ");";
%        }
    `interFct`
%    }
%
%    /* Repeat Counter */
%   if(inst.enableRepeatCounter){
%       let rpcArgs = inst.repeatCounter;
%       let rpcFct = "DL_"+flavorCat+"_setRepeatCounter("+inst.$name+"_INST, " +inst.$name + "_REPEAT_COUNT_"+rpcArgs+");\n";
    `rpcFct`
%   }
%
% /* Shadow load */
% if(inst.enableShadowLoad){
    DL_`flavorCat`_enableShadowFeatures(`inst.$name`_INST);
%} //if(inst.enableShadowLoad)
    DL_`flavorCat`_enableClock(`inst.$name`_INST);

%   /* Event Generation for Publisher Event Route 1 */
%
%   if ((inst.event1PublisherChannel != 0) &&
%       (inst.event1ControllerInterruptEn.length > 0)) {
%%{
    /* Event bit mask to be used in DL_TimerX_enableEvent() */
    var eventsToEnableOR = "(";

    for (let eventToEnable of inst.event1ControllerInterruptEn)
    {
        /* The last event should end with a closing parenthesis */
        if (eventToEnable == inst.event1ControllerInterruptEn[inst.event1ControllerInterruptEn.length - 1])
        {
            eventsToEnableOR += ("DL_"+ flavorCat.toUpperCase() + "_EVENT_" + eventToEnable + ")");
        }
        else
        {
            eventsToEnableOR += ("DL_"+ flavorCat.toUpperCase() + "_EVENT_" + eventToEnable + " |");
            eventsToEnableOR += "\n\t\t";
        }
    }
%%}
    DL_`flavorCat`_enableEvent(`inst.$name`_INST, DL_`flavorCat.toUpperCase()`_EVENT_ROUTE_1, `eventsToEnableOR`);

    DL_`flavorCat`_setPublisherChanID(`inst.$name`_INST, DL_`flavorCat.toUpperCase()`_PUBLISHER_INDEX_0, `inst.$name`_INST_PUB_0_CH);
%   }

%   /* Event Generation for Publisher Event Route 2 */
%
%   if ((inst.event2PublisherChannel != 0) &&
%       (inst.event2ControllerInterruptEn.length > 0)) {
%%{
    /* Event bit mask to be used in DL_TimerX_enableEvent() */
    var eventsToEnableOR = "(";

    for (let eventToEnable of inst.event2ControllerInterruptEn)
    {
        if (eventToEnable == inst.event2ControllerInterruptEn[inst.event2ControllerInterruptEn.length - 1])
        {
            eventsToEnableOR += ("DL_"+ flavorCat.toUpperCase() + "_EVENT_" + eventToEnable + ")");
        }
        else
        {
            eventsToEnableOR += ("DL_"+ flavorCat.toUpperCase() + "_EVENT_" + eventToEnable + " |");
            eventsToEnableOR += "\n\t\t";
        }
    }
%%}
    DL_`flavorCat`_enableEvent(`inst.$name`_INST, DL_`flavorCat.toUpperCase()`_EVENT_ROUTE_2, `eventsToEnableOR`);

    DL_`flavorCat`_setPublisherChanID(`inst.$name`_INST, DL_`flavorCat.toUpperCase()`_PUBLISHER_INDEX_1, `inst.$name`_INST_PUB_1_CH);
%   }

%   /* Event Generation for Subscriber Port */
%
%   if ((inst.subscriberPort != "Disabled") && (inst.subscriberChannel != 0)) {
%   let subscriberPort = inst.subscriberPort.split("FSUB")[1];
    DL_`flavorCat`_setExternalTriggerEvent(`inst.$name`_INST,
        DL_TIMER_EXT_TRIG_SEL_TRIG_SUB_`subscriberPort`);

    DL_`flavorCat`_enableExternalTrigger(`inst.$name`_INST);
%   // TODO: these values are static on setCaptureCompareInput. is this ok?
    DL_`flavorCat`_setCaptureCompareInput(`inst.$name`_INST,
        DL_TIMER_CC_INPUT_INV_NOINVERT, DL_TIMER_CC_IN_SEL_TRIG,
        DL_TIMER_CC_0_INDEX);

%   let triggerCondition = (inst.timerMode == "PERIODIC" && inst.counterZero == true) ? "ZCOND_TRIG_RISE" : "LCOND_TRIG_RISE";
    DL_`flavorCat`_setCaptureCompareCtl(`inst.$name`_INST, DL_TIMER_CC_MODE_CAPTURE,
        DL_TIMER_CC_`triggerCondition`, DL_TIMER_CC_0_INDEX);

    DL_`flavorCat`_setSubscriberChanID(`inst.$name`_INST,
        DL_TIMER_SUBSCRIBER_INDEX_`subscriberPort`, `inst.$name`_INST_SUB_`subscriberPort`_CH);
%   }

%   /* Cross-Triggering */
%
%   if(inst.crossTriggerEn){
%       let interArgs = "";
%       if(inst.crossTriggerAuthority == "Main"){
%%{
            let subsPort = "DL_TIMER_CROSS_TRIG_SRC_FSUB0";
            let enTrigCondSelect = "DISABLED";
            if(inst.mainCrossTriggerSource != "SW"){
                subsPort = "DL_TIMER_CROSS_TRIG_SRC_"+inst.mainCrossTriggerSource;
                enTrigCondSelect = "ENABLED";
            }
            let enInTrigCond = "DL_TIMER_CROSS_TRIGGER_INPUT_"+enTrigCondSelect;
%%}
%           let enCrossTrig = "DL_TIMER_CROSS_TRIGGER_MODE_ENABLED";
%           let crossTrigFct = "DL_"+flavorCat+"_configCrossTrigger("+inst.$name+"_INST, "+subsPort+",\n\t"+
%               enInTrigCond + ", " + enCrossTrig + "\n\t\t"+interArgs+");";
%           if(inst.mainCrossTriggerSource == "SW"){
     /* DL_TIMER_CROSS_TRIG_SRC is a Don't Care field when Cross Trigger Source is set to Software */
%           }
    `crossTrigFct`
%       } // if crossTriggerAuthority == "Main"
    /*
     * Determines the external triggering event to trigger the module (self-triggered in main configuration)
     * and triggered by specific timer in secondary configuration
     */
%%{
    let secCrossTrigSource = "";
    if(inst.crossTriggerAuthority == "Secondary"){
        if(inst.secondaryCrossTriggerSource.includes("Sub"))
            secCrossTrigSource = "SUB_"+inst.secondaryCrossTriggerSource.split("SubscriberPort")[1];
        else
            secCrossTrigSource = inst.secondaryCrossTriggerSource.split("Timer_")[1];
    }
    else{
        switch(flavor){
            case "TIMA0":
                secCrossTrigSource = "0";
                break;
            case "TIMA1":
                secCrossTrigSource = "1";
                break;
            case "TIMG7":
                secCrossTrigSource = "2";
                break;
            case "TIMG8":
                secCrossTrigSource = "3";
                break;
            case "TIMG12":
                secCrossTrigSource = "4";
                break;
            case "TIMG0":
                secCrossTrigSource = "0";
                break;
            case "TIMG1":
                secCrossTrigSource = "1";
                break;
            case "TIMG6":
                secCrossTrigSource = "1";
                break;
            case "TIMG2":
                secCrossTrigSource = "2";
                break;
            case "TIMG4":
                secCrossTrigSource = "3";
                break;
            default:
                /* do nothing */
                break;
        }
    }
%%}
    DL_`flavorCat`_setExternalTriggerEvent(`inst.$name`_INST,DL_TIMER_EXT_TRIG_SEL_TRIG_`secCrossTrigSource`);
    DL_`flavorCat`_enableExternalTrigger(`inst.$name`_INST);
%
%   } // if(inst.crossTriggerEn)
% if (inst.faultHandlerEn){
%%{
    let sourceCount = 0;
    var sourcesToEnableOR = "(";
    for (let sourceToEnable of inst.faultSource)
    {
        let printSource = "DL_TIMERA_FAULT_SOURCE_";
        switch(sourceToEnable){
            /* source is Fault Pin 0 */
            case "0":
                printSource+= "EXTERNAL_0_" + inst.faultPin0Sense;
            break;
            /* source is Fault Pin 1 */
            case "1":
                printSource+= "EXTERNAL_1_" + inst.faultPin1Sense;
            break;
            /* source is Fault Pin 2 */
            case "2":
                printSource+= "EXTERNAL_2_" + inst.faultPin2Sense;
            break;
            /* source is COMP0 */
            case "3":
                printSource+= "COMP0_" + inst.COMP0Sense;

            break;
            /* source is COMP1 */
            case "4":
                printSource+= "COMP1_" + inst.COMP1Sense;
            break;
            /* source is COMP2 */
            case "5":
                printSource+= "COMP2_" + inst.COMP2Sense;
            break;
        }
        if (sourceCount == 0)
        {
            sourcesToEnableOR += printSource;
        }
        else
        {
            sourcesToEnableOR += "\n\t\t";
            sourcesToEnableOR += " | " + printSource;
        }
        sourceCount++;
    }
    sourcesToEnableOR += ")";
%%}
% if(sourceCount >0){
    DL_`flavorCat`_setFaultSourceConfig(`inst.$name`_INST, `sourcesToEnableOR`);
% }
%%{
    let printConfig = "DL_TIMERA_FAULT_CONFIG_"+inst.faultTriggerIn+"\n\t\t"+
    " | "+"DL_TIMERA_FAULT_CONFIG_"+inst.faultConditionDuration+"\n\t\t"+
    " | "+"DL_TIMERA_FAULT_CONFIG_"+inst.faultInput+"\n\t\t"+
    " | "+"DL_TIMERA_FAULT_CONFIG_"+inst.faultInputEn;
%%}
DL_`flavorCat`_setFaultConfig(`inst.$name`_INST, `printConfig`);
% if(inst.faultInputFilterEn){
    DL_`flavorCat`_setFaultInputFilterConfig(`inst.$name`_INST,
    DL_TIMERA_FAULT_FILTER_FILTERED,
    DL_TIMERA_FAULT_FILTER_CPV_`inst.faultFilterType`,
    DL_TIMERA_FAULT_FILTER_FP_PER_`inst.faultFilterSamplePeriod`);
% }
% else {
    // DL_TIMERA_FAULT_FILTER_CPV_CONSEC_PER and DL_TIMERA_FAULT_FILTER_FP_PER_3 in this function are don't cares
    DL_`flavorCat`_setFaultInputFilterConfig(`inst.$name`_INST,
        DL_TIMERA_FAULT_FILTER_BYPASS,
        DL_TIMERA_FAULT_FILTER_CPV_`inst.faultFilterType`,
        DL_TIMERA_FAULT_FILTER_FP_PER_`inst.faultFilterSamplePeriod`);
% }
    DL_`flavorCat`_configFaultCounter(`inst.$name`_INST,
        DL_TIMERA_`inst.faultTimerCountEntry`, DL_TIMERA_`inst.faultTimerCountExit`);
% if(inst.faultInputDetect){
    DL_`flavorCat`_enableFaultInput(`inst.$name`_INST);
% }
% else{
    DL_`flavorCat`_disableFaultInput(`inst.$name`_INST);
% }
% if(inst.faultSrcClkDetect){
    DL_`flavorCat`_enableClockFaultDetection(`inst.$name`_INST);
% }
% else{
    DL_`flavorCat`_disableClockFaultDetection(`inst.$name`_INST);
% }
% }
}
% } // for i < instances.length
%

% if(crossTriggerMainEn){
SYSCONFIG_WEAK void SYSCFG_DL_TIMER_Cross_Trigger_init(void) {
%   for (let i in instances) {
%       let inst = instances[i];
%       let flavor = inst.peripheral.$solution.peripheralName;
%       let flavorCat = "Timer"+(flavor.replace(/[0-9]/g, '')).slice(3);
%if(inst.crossTriggerEn && inst.timerStartTimer && (inst.crossTriggerAuthority == "Main")){
    DL_`flavorCat`_generateCrossTrigger(`inst.$name`_INST);
%}
%   }
}
% }
%
% } // printFunction()
