/*
 *  Copyright (C) 2025 Texas Instruments Incorporated
 *
 *  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.
 */

/* STD include */
#include <stdlib.h>

/* SDK includes */
#include "device.h"
#include "log.h"
#include "dl_flash.h"

/* Syscfg includes */
#include "ti_sdk_dl_config.h"

/* ========================================================================== */
/*                          IMPORTANT NOTE                                    */
/* ========================================================================== */
/*
 * FLASH MEMORY ORGANIZATION:
 *
 * This example demonstrates flash programming operations on a device with
 * two flash banks:
 *
 * - BANK 0: Contains the APPLICATION CODE
 *   This bank stores the running application and MUST NOT be erased or
 *   modified during runtime, as doing so would erase the executing code
 *   and lead to UNDEFINED BEHAVIOR and system failure.
 *
 * - BANK 1: Used for FLASH OPERATIONS
 *   All flash programming, erasing, and testing operations in this example
 *   are performed ONLY on Bank 1 to safely demonstrate flash API usage
 *   without affecting the running application code.
 *
 * WARNING: Never erase or write to the same Bank while the application is
 * running from it, as this will corrupt the executing code.
 */

/* ========================================================================== */
/*                 Private Definitions and Macros                             */
/* ========================================================================== */
/* Flash buffer size in bytes (2048 bytes = 2KB) */
#define APP_FLASH_BUFFER_SIZE_BYTES (0x800U)

/* Test program sizes in bytes */
#define APP_FLASH_PROGRAM_SIZE_1 (APP_FLASH_BUFFER_SIZE_BYTES)
#define APP_FLASH_PROGRAM_SIZE_2 (100U)
#define APP_FLASH_PROGRAM_SIZE_3 (7U)

/* ========================================================================== */
/*                 Private Typedefs                                           */
/* ========================================================================== */

/* ========================================================================== */
/*                 Private Function Prototype                                 */
/* ========================================================================== */

/* ========================================================================== */
/*                 Private Variable Declaration                               */
/* ========================================================================== */

static uint8_t App_Flash_Buffer[APP_FLASH_BUFFER_SIZE_BYTES];

static bool Flash_Write_64_Bit(uint32_t address, uint8_t* data_buffer)
{
    bool result = false;

    if (DL_FlashCTL_acquireFlashSemaphore() == DL_FLASH_SUCCESS)
    {
        DL_FlashCTL_executeClearStatus(NVMNW);
        DL_FlashCTL_unprotectSector(NVMNW, address, DL_FLASHCTL_REGION_SELECT_MAIN);
        DL_FLASHCTL_COMMAND_STATUS command_status = DL_FlashCTL_programMemory64WithECCGenerated(NVMNW, address, ((uint32_t*)(&data_buffer[0])));
        if (command_status == DL_FLASHCTL_COMMAND_STATUS_PASSED)     // proceed if the programming operation has passed
        {
            volatile uint8_t check_value_target = ((uint8_t*)(address))[0u];
            volatile uint8_t check_value_source = data_buffer[0];
            if ((check_value_target == check_value_source)) // verify whether correct data was written (first byte)
            {
                result = true;
            }
        }
        if (DL_FlashCTL_releaseFlashSemaphore() != DL_FLASH_SUCCESS)     // semaphore should be released successfully
        {
            result = false;
        }
    }

    return result;
}

/* ========================================================================== */
/*                 Public Functions                                           */
/* ========================================================================== */
int main(void)
{
    uint32_t status;
    uint32_t programSize1 = APP_FLASH_PROGRAM_SIZE_1;
    uint32_t programSize2 = APP_FLASH_PROGRAM_SIZE_2;
    uint32_t programSize3 = APP_FLASH_PROGRAM_SIZE_3;
    uint32_t sectorAddr;
    uint32_t numSector = 0U;
    uint32_t i;

    /* Call the Device Init and SYSCFG Init functions */
    Device_Init();
    SYSCFG_DL_init();

    /* Fill a buffer with data to program into the flash */
    for (i = 0U; i < APP_FLASH_BUFFER_SIZE_BYTES; i++)
    {
        App_Flash_Buffer[i] = (uint8_t)(i & 0xFFU);
    }

    /* Inactive Bank Erase */
    status = DL_Flash_eraseBank(NVMNW_BANK1_MAIN_ADDRESS);
    LOG_ASSERT(status == DL_FLASH_SUCCESS, "Bank erase failed with status: 0x%X\n", status);
    LOG("Bank at address 0x%08X erased successfully\n\n", NVMNW_BANK1_MAIN_ADDRESS);

    uint16_t count = 256u;
    uint32_t addr = NVMNW_BANK1_MAIN_ADDRESS;
    uint16_t source_addr_offset = 0u;     // offset to track the position in the source
    
    while (count > 0u)     // as long as data is to be written
    {
        bool is_written = Flash_Write_64_Bit(addr, (uint8_t*)(&(App_Flash_Buffer[source_addr_offset])));
        LOG_ASSERT(is_written == true, "Failed");
        
        addr += 8u;
        source_addr_offset += 8u;
        count--;      
    }
    LOG("Success");

    /* Inactive Bank Erase */
    status = DL_Flash_eraseBank(NVMNW_BANK1_MAIN_ADDRESS);
    LOG_ASSERT(status == DL_FLASH_SUCCESS, "Bank erase failed with status: 0x%X\n", status);
    LOG("Bank at address 0x%08X erased successfully\n\n", NVMNW_BANK1_MAIN_ADDRESS);

    uint64_t var = 0x7777777777777777;
    bool is_written = Flash_Write_64_Bit(NVMNW_BANK1_MAIN_ADDRESS, (uint8_t*)&var);
    LOG_ASSERT(is_written == true, "Failed");
    LOG("Success");

    return 0;
}
