//###########################################################################
//
// FILE:   ethercat_slave_cm_hal.c
//
// TITLE:  CM EtherCAT HAL Driver.
//
// This contains the source of the CM HAL APIs required by EtherCAT stack
// as well as HAL PDI test application.
//
//###########################################################################
// $TI Release: F2838x EtherCAT Software v2.02.00.00 $
// $Release Date: Fri Nov 17 18:58:50 IST 2023 $
// $Copyright:
// Copyright (C) 2023 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.
// $
//###########################################################################

//
// Included Files
//
#include "ethercat_slave_cm_hal.h"

#ifdef PDI_HAL_TEST

//
// HAL Test Application - Register Debug Structure
//
ESC_DebugRegisters ESC_escRegs[ESC_HAL_TEST_DEBUG_REGS_LENGTH];

//
// HAL Block Data Arrays
//
static uint32_t ESC_writeBlockData[ESC_HAL_TEST_BLOCK_LENGTH / 4U];
static uint32_t ESC_readBlockData[ESC_HAL_TEST_BLOCK_LENGTH / 4U];

#endif // PDI_HAL_TEST

//*****************************************************************************
//
// ESC_getTimer
//
//*****************************************************************************
uint32_t
ESC_getTimer(void)
{
    //
    // Return 1's compliment of the CPU timer
    //
    return(~((uint32_t)CPUTimer_getTimerCount(CPUTIMER0_BASE)));
}

//*****************************************************************************
//
// ESC_clearTimer
//
//*****************************************************************************
void
ESC_clearTimer(void)
{
    //
    // Set the timer period count
    //
    CPUTimer_setPeriod(CPUTIMER0_BASE, 0xFFFFFFFFUL);

    //
    // Reload timer with the period count value
    //
    CPUTimer_reloadTimerCounter(CPUTIMER0_BASE);
}

//*****************************************************************************
//
// ESC_timerIncPerMilliSec
//
//*****************************************************************************
uint32_t
ESC_timerIncPerMilliSec(void)
{
    //
    // Returns value based on core frequency of 125MHz.
    //
    return((uint32_t)125000UL);
}

//*****************************************************************************
//
// ESC_readBlockISR
//
//*****************************************************************************
void
ESC_readBlockISR(ESCMEM_ADDR *pData, uint16_t address, uint16_t len)
{
    //
    // Create pointer to ESC Address
    //
    const void * escSource = (void *)(ESC_BASE + (uint32_t)address);

    //
    // Copy ESC data to buffer
    //
    memcpy(pData, escSource, (size_t)len);
}

//*****************************************************************************
//
// ESC_readBlock
//
//*****************************************************************************
void
ESC_readBlock(ESCMEM_ADDR *pData, uint16_t address, uint16_t len)
{
    //
    // Disables interrupts
    //
    _disable_IRQ();

    //
    // Perform copy of ESC data to buffer
    //
    ESC_readBlockISR(pData, address, len);

    //
    // Enable interrupts
    //
    _enable_IRQ();
}

//*****************************************************************************
//
// ESC_readDWordISR
//
//*****************************************************************************
uint32_t
ESC_readDWordISR(uint16_t address)
{
    //
    // Read 32-bit address from ESC memory
    //
    return(HWREG(ESC_BASE + address));
}

//*****************************************************************************
//
// ESC_readDWord
//
//*****************************************************************************
uint32_t
ESC_readDWord(uint16_t address)
{
    uint32_t dWordValue;

    //
    // Disables interrupts
    //
    _disable_IRQ();

    //
    // Read 32-bit address from ESC memory
    //
    dWordValue = ESC_readDWordISR(address);

    //
    // Enable interrupts
    //
    _enable_IRQ();

    //
    // Return value
    //
    return(dWordValue);
}

//*****************************************************************************
//
// ESC_readWordISR
//
//*****************************************************************************
uint16_t
ESC_readWordISR(uint16_t address)
{
    //
    // Read 16-bit address from ESC memory
    //
    return(HWREGH(ESC_BASE + address));
}

//*****************************************************************************
//
// ESC_readWord
//
//*****************************************************************************
uint16_t
ESC_readWord(uint16_t address)
{
    uint16_t wordValue;

    //
    // Disables interrupts
    //
    _disable_IRQ();

    //
    // Read 16-bit address from ESC memory
    //
    wordValue = ESC_readWordISR(address);

    //
    // Enable interrupts
    //
    _enable_IRQ();

    //
    // Return value
    //
    return(wordValue);
}

//*****************************************************************************
//
// ESC_readByteISR
//
//*****************************************************************************
uint8_t
ESC_readByteISR(uint16_t address)
{
    //
    // Read 8-bit address from ESC memory
    //
    return(HWREGB(ESC_BASE + address));
}

//*****************************************************************************
//
// ESC_readByte
//
//*****************************************************************************
uint8_t
ESC_readByte(uint16_t address)
{
    uint8_t byteValue;

    //
    // Disables interrupts
    //
    _disable_IRQ();

    //
    // Read 8-bit address from ESC memory
    //
    byteValue = ESC_readByteISR(address);

    //
    // Enable interrupts
    //
    _enable_IRQ();

    //
    // Return Value
    //
    return(byteValue);
}

//*****************************************************************************
//
// ESC_writeBlockISR
//
//*****************************************************************************
void
ESC_writeBlockISR(ESCMEM_ADDR *pData, uint16_t address, uint16_t len)
{
    //
    // Create pointer to ESC Address
    //
    void * escDest = (void *)(ESC_BASE + (uint32_t)address);

    //
    // Copy buffer data to ESC memory
    //
    memcpy(escDest, pData, (size_t)len);
}

//*****************************************************************************
//
// ESC_writeBlock
//
//*****************************************************************************
void
ESC_writeBlock(ESCMEM_ADDR *pData, uint16_t address, uint16_t len)
{
    //
    // Disables interrupts
    //
    _disable_IRQ();

    //
    // Write data buffer into ESC memory
    //
    ESC_writeBlockISR(pData, address, len);

    //
    // Enable interrupts
    //
    _enable_IRQ();
}

//*****************************************************************************
//
// ESC_writeDWordISR
//
//*****************************************************************************
void
ESC_writeDWordISR(uint32_t dWordValue, uint16_t address)
{
    //
    // Write two 16-bit words to ESC memory
    //
    HWREG(ESC_BASE + address) = dWordValue;
}

//*****************************************************************************
//
// ESC_writeDWord
//
//*****************************************************************************
void
ESC_writeDWord(uint32_t dWordValue, uint16_t address)
{
    //
    // Disables interrupts
    //
    _disable_IRQ();

    //
    // Write two 16-words into ESC memory
    //
    ESC_writeDWordISR(dWordValue, address);

    //
    // Enable interrupts
    //
    _enable_IRQ();
}

//*****************************************************************************
//
// ESC_writeWordISR
//
//*****************************************************************************
void
ESC_writeWordISR(uint16_t wordValue, uint16_t address)
{
    //
    // Write 16-bit word into ESC memory
    //
    HWREGH(ESC_BASE + address) = wordValue;
}

//*****************************************************************************
//
// ESC_writeWord
//
//*****************************************************************************
void
ESC_writeWord(uint16_t wordValue, uint16_t address)
{
    //
    // Disables interrupts
    //
    _disable_IRQ();

    //
    // Write one 16-word into ESC memory
    //
    ESC_writeWordISR(wordValue, address);

    //
    // Enable interrupts
    //
    _enable_IRQ();
}

//*****************************************************************************
//
// ESC_writeByteISR
//
//*****************************************************************************
void
ESC_writeByteISR(uint8_t byteValue, uint16_t address)
{
    //
    // Write 8-bit data into ESC memory
    //
    HWREGB(ESC_BASE + address) = byteValue;
}

//*****************************************************************************
//
// ESC_writeByte
//
//*****************************************************************************
void
ESC_writeByte(uint8_t byteValue, uint16_t address)
{
    //
    // Disables interrupts
    //
    _disable_IRQ();

    //
    // Write one byte into ESC memory
    //
    ESC_writeByteISR(byteValue, address);

    //
    // Enable interrupts
    //
    _enable_IRQ();
}

//*****************************************************************************
//
// ESC_setLed
//
//*****************************************************************************
void
ESC_setLed(uint8_t runLed, uint8_t errLed)
{
    //
    // Set/Clear Run LED
    //
    GPIO_writePin(ESC_RUN_LED_GPIO, (uint32_t)(runLed));

    //
    // Set/Clear Error LED
    //
    GPIO_writePin(ESC_ERR_LED_GPIO, (uint32_t)(errLed));
}

#ifdef PDI_HAL_TEST
//*****************************************************************************
//
// HAL_performDelay
//
//*****************************************************************************
void HAL_performDelay(void)
{
    uint32_t i;

    //
    // Perform software delay
    //
    for(i = 0U; i < 0xFFFFF; i++)
    {
        NOP;
    }
}

//*****************************************************************************
//
// HAL_initWriteBlockData
//
//*****************************************************************************
void HAL_initWriteBlockData(void)
{
    uint16_t i;

    //
    // Initialize write block data array
    //
    for(i = 0U; i < (ESC_HAL_TEST_BLOCK_LENGTH / 4U); i++)
    {
        ESC_writeBlockData[i] = 0x1234ABCDUL;
    }
}

//*****************************************************************************
//
// HAL_clearReadBlockData
//
//*****************************************************************************
void HAL_clearReadBlockData(void)
{
    uint16_t i;

    //
    // Clear read block data array
    //
    for(i = 0U; i < (ESC_HAL_TEST_BLOCK_LENGTH / 4U); i++)
    {
        ESC_readBlockData[i] = 0x0UL;
    }
}

//*****************************************************************************
//
// HAL_testBlockData
//
//*****************************************************************************
uint16_t HAL_testBlockData(uint16_t length)
{
    uint16_t i;
    uint8_t * writeData = (uint8_t *)(&ESC_writeBlockData[0]);
    uint8_t * readData = (uint8_t *)(&ESC_readBlockData[0]);

    //
    // Check that data written and data read match
    //
    for(i = 0U; i < length; i++)
    {
        if(*writeData != *readData)
        {
            return(ESC_HAL_BLOCK_TEST_FAIL);
        }

        writeData++;
        readData++;
    }

    return(ESC_HAL_BLOCK_TEST_PASS);
}

//*****************************************************************************
//
// ESC_setupPDITestInterface
//
//*****************************************************************************
void
ESC_setupPDITestInterface(void)
{
    uint16_t currentAddress = 0x0U;
    uint32_t doubleWordData = 0x0UL;
    uint16_t wordData = 0x0U;
    uint8_t byteData = 0x0U;

    //
    // Setup and add various ESC registers to monitor
    //
    ESC_debugInitESCRegLogs();
    ESC_debugAddESCRegsAddress(0x0U);     // Type, Revision
    ESC_debugAddESCRegsAddress(0x2U);     // Build
    ESC_debugAddESCRegsAddress(0x4U);     // FMMUs, SyncManagers Supported
    ESC_debugAddESCRegsAddress(0x8U);     // ESC Supported Features
    ESC_debugAddESCRegsAddress(0x100U);   // DL Control
    ESC_debugAddESCRegsAddress(0x102U);   // DL Control (Extended)
    ESC_debugAddESCRegsAddress(0x110U);   // DL Status
    ESC_debugAddESCRegsAddress(0x310U);   // Lost Link Counter 1
    ESC_debugAddESCRegsAddress(0x312U);   // Lost Link Counter 2
    ESC_debugAddESCRegsAddress(0x510U);   // MII Control/Status
    ESC_debugAddESCRegsAddress(0x512U);   // PHY Address
    ESC_debugAddESCRegsAddress(0x514U);   // PHY Data
    ESC_debugAddESCRegsAddress(0x516U);   // MII ECAT Access State
    ESC_debugAddESCRegsAddress(0x518U);   // PHY Port Status (1)
    ESC_debugAddESCRegsAddress(0x51AU);   // PHY Port Status (2)
    ESC_debugAddESCRegsAddress(0x1000U);  // First data word of ESC RAM

    //
    // Check that correct PDI type (ASYNC16) is configured
    //
    if(ESC_readByte(ESC_O_PDI_CONTROL) != ESC_PDI_CONTROL_ASYNC16)
    {
        //
        // PDI not operational or incorrect
        //
        while(1)
        {
            //
            // Toggle Error
            //
            ESC_signalFail();
        }
    }

    //
    // Perform PDI read and write tests for entire ESC PDI RAM range
    //
    for(currentAddress = ESC_PDI_RAM_START_ADDRESS_OFFSET;
        currentAddress <= ESC_PDI_RAM_END_ADDRESS_OFFSET;
        currentAddress += 4U)
    {
        //
        // Read DWord and Write DWord API Tests
        //
        doubleWordData = ESC_readDWord(currentAddress);
        ESC_writeDWord(0xABCD1234UL, currentAddress);
        doubleWordData = ESC_readDWord(currentAddress);

        if(doubleWordData != 0xABCD1234UL)
        {
            while(1)
            {
                //
                // Toggle Error
                //
                ESC_signalFail();
            }
        }

        doubleWordData = ESC_readDWordISR(currentAddress);
        ESC_writeDWordISR(0x1A2B3C4DUL, currentAddress);
        doubleWordData = ESC_readDWordISR(currentAddress);

        if(doubleWordData != 0x1A2B3C4DUL)
        {
            while(1)
            {
                //
                // Toggle Error
                //
                ESC_signalFail();
            }
        }

        //
        // Read Word and Write Word API Tests
        //
        wordData = ESC_readWord(currentAddress);
        ESC_writeWord(0x6789U, currentAddress);
        wordData = ESC_readWord(currentAddress);

        if(wordData != 0x6789U)
        {
            while(1)
            {
                //
                // Toggle Error
                //
                ESC_signalFail();
            }
        }

        wordData = ESC_readWordISR(currentAddress);
        ESC_writeWordISR(0x5A5AU, currentAddress);
        wordData = ESC_readWordISR(currentAddress);

        if(wordData != 0x5A5AU)
        {
            while(1)
            {
                //
                // Toggle Error
                //
                ESC_signalFail();
            }
        }

        //
        // Read Byte and Write Byte API Tests
        //
        byteData = ESC_readByte(currentAddress);
        ESC_writeByte(0xEFU, currentAddress);
        byteData = ESC_readByte(currentAddress);

        if(byteData != 0xEFU)
        {
            while(1)
            {
                //
                // Toggle Error
                //
                ESC_signalFail();
            }
        }

        byteData = ESC_readByteISR(currentAddress);
        ESC_writeByteISR(0xBCU, currentAddress);
        byteData = ESC_readByteISR(currentAddress);

        if(byteData != 0xBCU)
        {
            while(1)
            {
                //
                // Toggle Error
                //
                ESC_signalFail();
            }
        }
    }

    //
    // Setup for read/write block API Tests
    //
    HAL_initWriteBlockData();

    //
    // Perform even length write and read block (non-ISR) API Test
    //
    ESC_writeBlock((uint8_t *)(&ESC_writeBlockData[0]),
                   ESC_PDI_RAM_START_ADDRESS_OFFSET,
                   ESC_HAL_TEST_BLOCK_LENGTH);
    ESC_readBlock((uint8_t *)(&ESC_readBlockData[0]),
                  ESC_PDI_RAM_START_ADDRESS_OFFSET,
                  ESC_HAL_TEST_BLOCK_LENGTH);

    if(HAL_testBlockData(ESC_HAL_TEST_BLOCK_LENGTH) != ESC_HAL_BLOCK_TEST_PASS)
    {
        while(1)
        {
            //
            // Toggle Error
            //
            ESC_signalFail();
        }
    }

    HAL_clearReadBlockData();

    //
    // Perform even length write and read block API Test
    //
    ESC_writeBlockISR((uint8_t *)(&ESC_writeBlockData[0]),
                      (ESC_PDI_RAM_START_ADDRESS_OFFSET + 0x1000U),
                      ESC_HAL_TEST_BLOCK_LENGTH);
    ESC_readBlockISR((uint8_t *)(&ESC_readBlockData[0]),
                     (ESC_PDI_RAM_START_ADDRESS_OFFSET + 0x1000U),
                     ESC_HAL_TEST_BLOCK_LENGTH);

    if(HAL_testBlockData(ESC_HAL_TEST_BLOCK_LENGTH) != ESC_HAL_BLOCK_TEST_PASS)
    {
        while(1)
        {
            //
            // Toggle Error
            //
            ESC_signalFail();
        }
    }

    HAL_clearReadBlockData();

    //
    // Perform odd length write and read block (non-ISR) API Test
    //
    ESC_writeBlock((uint8_t *)(&ESC_writeBlockData[0]),
                   (ESC_PDI_RAM_START_ADDRESS_OFFSET + 0x2000U),
                   (ESC_HAL_TEST_BLOCK_LENGTH - 1U));
    ESC_readBlock((uint8_t *)(&ESC_readBlockData[0]),
                  (ESC_PDI_RAM_START_ADDRESS_OFFSET + 0x2000U),
                  (ESC_HAL_TEST_BLOCK_LENGTH - 1U));

    if(HAL_testBlockData((ESC_HAL_TEST_BLOCK_LENGTH - 1U)) !=
       ESC_HAL_BLOCK_TEST_PASS)
    {
        while(1)
        {
            //
            // Toggle Error
            //
            ESC_signalFail();
        }
    }

    HAL_clearReadBlockData();

    //
    // Perform odd length write and read block API Test
    //
    ESC_writeBlockISR((uint8_t *)(&ESC_writeBlockData[0]),
                      (ESC_PDI_RAM_START_ADDRESS_OFFSET + 0x3000U),
                      (ESC_HAL_TEST_BLOCK_LENGTH - 1U));
    ESC_readBlockISR((uint8_t *)(&ESC_readBlockData[0]),
                     (ESC_PDI_RAM_START_ADDRESS_OFFSET + 0x3000U),
                     (ESC_HAL_TEST_BLOCK_LENGTH - 1U));

    if(HAL_testBlockData((ESC_HAL_TEST_BLOCK_LENGTH - 1U)) !=
       ESC_HAL_BLOCK_TEST_PASS)
    {
        while(1)
        {
            //
            // Toggle Error
            //
            ESC_signalFail();
        }
    }

    //
    // Pass
    //
    ESC_signalPass();
}

//*****************************************************************************
//
// ESC_debugUpdateESCRegLogs
//
//*****************************************************************************
void
ESC_debugUpdateESCRegLogs(void)
{
    uint16_t i = 0U;

    //
    // Update ESC register data into debug array
    //
    while(ESC_escRegs[i].address != 0xFFFFU)
    {
        ESC_escRegs[i].data = ESC_readWord(ESC_escRegs[i].address);
        i++;
    }
}

//*****************************************************************************
//
// ESC_debugAddESCRegsAddress
//
//*****************************************************************************
void
ESC_debugAddESCRegsAddress(uint16_t address)
{
    uint16_t i = 0U;

    //
    // Add ESC Register Address to debug array
    //
    for(i = 0U; i < ESC_HAL_TEST_DEBUG_REGS_LENGTH; i++)
    {
        if(ESC_escRegs[i].address == 0xFFFFU)
        {
            ESC_escRegs[i].address = address;
            return;
        }
    }
}

//*****************************************************************************
//
// ESC_debugInitESCRegLogs
//
//*****************************************************************************
void
ESC_debugInitESCRegLogs(void)
{
    uint16_t i = 0U;

    //
    // Initialize ESC register debug array
    //
    for(i = 0U; i < ESC_HAL_TEST_DEBUG_REGS_LENGTH ; i++)
    {
        ESC_escRegs[i].address = 0xFFFFU;
        ESC_escRegs[i].data = 0xFFFFU;
    }
}

//*****************************************************************************
//
// ESC_signalPass
//
//*****************************************************************************
void
ESC_signalPass(void)
{
    //
    // Turn on controlCARD LEDs
    //
    GPIO_writePin(CCARD_LED_1_GPIO, 0UL);
    GPIO_writePin(CCARD_LED_2_GPIO, 0UL);
}

//*****************************************************************************
//
// ESC_signalFail
//
//*****************************************************************************
void
ESC_signalFail(void)
{
    //
    // Toggle controlCARD LEDs and delay
    //
    GPIO_togglePin(CCARD_LED_1_GPIO);
    GPIO_togglePin(CCARD_LED_2_GPIO);

    HAL_performDelay();
}

//*****************************************************************************
//
// ESC_passFailSignalSetup
//
//*****************************************************************************
void
ESC_passFailSignalSetup(void)
{
    //
    // LED GPIO configuration completed by CPU1
    //

    //
    // Turn off controlCARD LEDs
    //
    GPIO_writePin(CCARD_LED_1_GPIO, 1UL);
    GPIO_writePin(CCARD_LED_2_GPIO, 1UL);
}
#endif // PDI_HAL_TEST

//*****************************************************************************
//
// ESC_loadedCheckEEPROM
//
//*****************************************************************************
uint16_t
ESC_loadedCheckEEPROM(void)
{
    uint16_t status;

    //
    // Get ESC DL Status register
    //
    status = ESC_readWord(ESC_O_DL_STATUS);

    //
    // Check if EEPROM is loaded
    //
    if((status & ESC_DL_STATUS_EEPROMLOAD_M) == ESC_DL_STATUS_EEPROMLOAD_M)
    {
        //
        // Get ESC EEPROM Status register
        //
        status = ESC_readWord(ESC_O_EEPROM_STATUS);

        //
        // Check if EEPROM is loaded and device information is okay
        //
        if((status & ESC_EEPROM_STATUS_EEPROMLOAD_M) == ESC_EEPROM_SUCCESS)
        {
            return(ESC_EEPROM_SUCCESS);
        }
        else
        {
            return(ESC_EEPROM_LOAD_ERROR);
        }
    }
    else
    {
        //
        // DL Status indicated EEPROM is not loaded
        //
        return(ESC_EEPROM_NOT_LOADED);
    }
}

//*****************************************************************************
//
// ESC_resetESC
//
//*****************************************************************************
void
ESC_resetESC(void)
{
    SysCtl_resetPeripheral(SYSCTL_PERIPH_RES_ECAT);
}

//*****************************************************************************
//
// ESC_holdESCInReset
//
//*****************************************************************************
void
ESC_holdESCInReset(void)
{
    //
    // Put ESC in reset
    //
    HWREG(CMSYSCTL_BASE + SYSCTL_O_CMSOFTPRESET1) |=
         (SYSCTL_CMSOFTPRESET1_ETHERCAT |
          (((uint32_t)SYSCTL_CMSYSCTL_KEY << 16U ) &
           SYSCTL_CMSOFTPRESET1_KEY_M));
}

//*****************************************************************************
//
// ESC_releaseESCReset
//
//*****************************************************************************
void
ESC_releaseESCReset(void)
{
    //
    // Release from reset
    //
    HWREG(CMSYSCTL_BASE + SYSCTL_O_CMSOFTPRESET1) =
          ((HWREG(CMSYSCTL_BASE + SYSCTL_O_CMSOFTPRESET1) &
            (~SYSCTL_CMSOFTPRESET1_ETHERCAT)) |
           (((uint32_t)SYSCTL_CMSYSCTL_KEY << 16U ) &
            SYSCTL_CMSOFTPRESET1_KEY_M));
}

//*****************************************************************************
//
// ESC_initHW
//
//*****************************************************************************
uint16_t
ESC_initHW(void)
{
    //
    // Set application-specific timeout for waiting for EEPROM to load
    // and one for waiting for memory initialization
    // (End user can adjust as needed)
    //
    uint16_t eepromTimeOut = 0x1000U;
    uint16_t memoryTimeOut = 0x300U;

    //
    // Initialize CM - Disable watchdog, enable peripherals
    //                 (Device clocking setup by CPU1)
    //
    CM_init();

    //
    // Initialize ESC GPIOs
    //
    // Already setup and initialized by CPU1
    //

    //
    // Register EtherCAT Interrupt Handlers
    //
    Interrupt_registerHandler(INT_ECAT, &ESC_applicationLayerHandler);
    Interrupt_registerHandler(INT_ECAT_SYNC0, &ESC_applicationSync0Handler);
    Interrupt_registerHandler(INT_ECAT_SYNC1, &ESC_applicationSync1Handler);

    //
    // Enable ECAT/PDI, Sync0, and Sync1 interrupts in NVIC
    //
    Interrupt_enable(INT_ECAT);
    Interrupt_enable(INT_ECAT_SYNC0);
    Interrupt_enable(INT_ECAT_SYNC1);

    //
    // Configure and Start timer
    //
    CPUTimer_setPeriod(CPUTIMER0_BASE, 0xFFFFFFFFUL);
    CPUTimer_setPreScaler(CPUTIMER0_BASE, 0U);
    CPUTimer_startTimer(CPUTIMER0_BASE);

#ifdef PDI_HAL_TEST
    //
    // Enable Pass, fail signals for HAL PDI Test
    //
    ESC_passFailSignalSetup();
#endif // PDI_HAL_TEST

    //
    // Configure EEPROM Size for 16K bits or less
    //
    ESCSS_configureEEPROMSize(ESC_SS_CONFIG_BASE, ESCSS_LESS_THAN_16K);

    //
    // Reset ESC
    //
    ESC_resetESC();

#ifdef PDI_HAL_TEST
    //
    // Enable the debug access
    //
    while((HWREGH(ESC_SS_BASE + ESCSS_O_ACCESS_CTRL) &
           ESCSS_ACCESS_CTRL_ENABLE_DEBUG_ACCESS) !=
          ESCSS_ACCESS_CTRL_ENABLE_DEBUG_ACCESS)
    {
        ESCSS_enableDebugAccess(ESC_SS_BASE);
    }
#endif // PDI_HAL_TEST

    //
    // Initialize ESCSS Memory
    //
    ESCSS_initMemory(ESC_SS_BASE);

    //
    // Wait for ESCSS memory initialization to complete
    //
    if(ESCSS_getMemoryInitDoneStatusBlocking(ESC_SS_BASE, memoryTimeOut) !=
       ESCSS_API_SUCCESS)
    {
        return(ESC_HW_INIT_FAIL);
    }

    //
    // Wait (with time out) for EEPROM to be loaded
    //
    while(ESC_loadedCheckEEPROM() != ESC_EEPROM_SUCCESS)
    {
        eepromTimeOut--;

        //
        // On time out, return fail
        //
        if(eepromTimeOut == 0U)
        {
            return(ESC_HW_INIT_FAIL);
        }
    }

    //
    // Initialize AL Event Mask to zero to prevent ESC interrupts until
    // set during stack state transition to SAFEOP
    //
    ESC_writeDWord(0UL, ESC_O_AL_EVENTMASK);

    //
    // Enable ECAT/PDI, Sync0, and Sync1 interrupts in ESCSS
    //
    ESCSS_setMaskedInterruptStatus(ESC_SS_BASE,
                                   (ESCSS_INTR_MASK_IRQ_MASK |
                                    ESCSS_INTR_MASK_SYNC0_MASK |
                                    ESCSS_INTR_MASK_SYNC1_MASK));

    //
    // Connect ESCSS Sync0/1 signals to respective interrupts in NVIC
    //
    ESCSS_configureSync0Connections(ESC_SS_BASE, ESCSS_SYNC0_CONFIG_CM4_NVIC_EN,
                                    ESCSS_VALID_KEY_VALUE);
    ESCSS_configureSync1Connections(ESC_SS_BASE, ESCSS_SYNC1_CONFIG_CM4_NVIC_EN,
                                    ESCSS_VALID_KEY_VALUE);

    //
    // Enable interrupts to CM
    //
    _enable_IRQ();

    return(ESC_HW_INIT_SUCCESS);
}

//*****************************************************************************
//
// ESC_releaseHW
//
//*****************************************************************************
void
ESC_releaseHW(void)
{
    //
    // Intentionally empty - Implementation is left to the end user
    //
}

//*****************************************************************************
//
// ESC_applicationLayerHandler
//
//*****************************************************************************
__interrupt void
ESC_applicationLayerHandler(void)
{
#ifdef ETHERCAT_STACK
#if AL_EVENT_ENABLED
    //
    // When stack is included and application event enabled, call stack PDI ISR
    //
    PDI_Isr();
#endif  // AL_EVENT_ENABLED
#endif  // ETHERCAT_STACK

    //
    // Acknowledge and clear interrupt
    //
    ESCSS_clearRawInterruptStatus(ESC_SS_BASE, ESCSS_INTR_CLR_IRQ_CLR);
}

//*****************************************************************************
//
// ESC_applicationSync0Handler
//
//*****************************************************************************
__interrupt void
ESC_applicationSync0Handler(void)
{
#ifdef ETHERCAT_STACK
#if DC_SUPPORTED
    //
    // When stack is included and DC is enabled, call stack Sync0 ISR
    //
    Sync0_Isr();
#endif  // DC_SUPPORTED
#endif  // ETHERCAT_STACK

    //
    // Acknowledge and clear interrupt
    //
    ESCSS_clearRawInterruptStatus(ESC_SS_BASE, ESCSS_INTR_CLR_SYNC0_CLR);
}

//*****************************************************************************
//
// ESC_applicationSync1Handler
//
//*****************************************************************************
__interrupt void
ESC_applicationSync1Handler(void)
{
#ifdef ETHERCAT_STACK
#if DC_SUPPORTED
    //
    // When stack is included and DC is enabled, call stack Sync1 ISR
    //
    Sync1_Isr();
#endif  // DC_SUPPORTED
#endif  // ETHERCAT_STACK

    //
    // Acknowledge and clear interrupt
    //
    ESCSS_clearRawInterruptStatus(ESC_SS_BASE, ESCSS_INTR_CLR_SYNC1_CLR);
}

//
// End of File
//
