/**
 * @file    flash_storage.c
 */

#include "flash_manager.h"

/**
 * @brief Grava a página inteira de uma vez.
 * @param pPage Ponteiro para a estrutura de 1KB na RAM.
 * @return HAL_OK em caso de sucesso.
 */

FlashPage_t flash_data;

HAL_StatusTypeDef Flash_Save_Page(FlashPage_t *pPage) {
    if (pPage == NULL) return HAL_ERROR;

    HAL_StatusTypeDef status = HAL_OK;

    HAL_FLASH_Unlock();

    // 1. Apagar a página inteira (limpa os 1024 bytes)
    FLASH_EraseInitTypeDef EraseInitStruct;
    uint32_t PageError = 0;

    EraseInitStruct.TypeErase     = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.PageAddress   = FLASH_PAGE_ADDR;
    EraseInitStruct.NbPages       = 1;

    if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) {
        status = HAL_ERROR;
        goto Exit;
    }

    // 2. Gravar o bloco de 1KB
    // Como a estrutura é exatamente 1KB e alinhada, podemos tratar como um array de uint32_t.
    // O STM32F1 grava preferencialmente em DoubleWord (64-bit), mas HalfWord (16-bit)
    // funciona de forma segura para qualquer tamanho múltiplo de 2.
    uint32_t *pSrc = (uint32_t *)pPage;
    uint32_t *pDest = (uint32_t *)FLASH_PAGE_ADDR;
    uint32_t iterations = FLASH_PAGE_SIZE / sizeof(uint32_t); // 1024 / 4 = 256 iterações

    for (uint32_t i = 0; i < iterations; i++) {
        // Usamos o modo de gravação de 32-bit (Word) se disponível,
        // ou simulamos com duas gravações de 16-bit para máxima compatuidade no F1.
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)&pDest[i], pSrc[i]) != HAL_OK) {
            status = HAL_ERROR;
            break;
        }
    }

Exit:
    HAL_FLASH_Lock();
    return status;
}

/**
 * @brief Lê a página da Flash para a RAM.
 */
HAL_StatusTypeDef Flash_Load_Page(FlashPage_t *pDest) {
    if (pDest == NULL) return HAL_ERROR;

    // Leitura direta por memcpy (A Flash é mapeada no espaço de endereçamento comum)
    memcpy(pDest, (void *)FLASH_PAGE_ADDR, FLASH_PAGE_SIZE);

    // Validação da integridade através do Magic Number
    if (pDest->magic_number != 0xDEADBEEF) {
        return HAL_ERROR;
    }

    return HAL_OK;
}
