/******************************************************************************
 * @file        File_Handle.c
 * @brief       BMP图片文件处理和Flash存储管理文件
 * @details     本文件实现了BMP图片文件的处理功能，包括BMP文件头结构定义、
 *              Flash存储读写操作、LOGO图片的保存和显示等功能。
 *              支持将BMP格式的LOGO图片数据保存到Flash中，并在需要时读取显示。
 * @author      阜阳师范大学物电学院
 * @version     V0.1
 * @date        2026.1.23
 * @note        Flash存储地址：0x0803F000（扇区126）
 *              Flash扇区大小：2KB
 *              BMP数据长度：3208字节
 ******************************************************************************/

/* ============================================================================
 * 头文件包含
 * ============================================================================ */
#include "filehandle.h"
#include <string.h>
#include <stdio.h>

/* ============================================================================
 * 私有宏定义
 * ============================================================================ */
#define Flash_EndAddr           (0x08040000)  /**< Flash存储结束地址 */
#define SECTOR_SIZE             (2048)       /**< Flash扇区大小，单位：字节（2KB） */

/* ============================================================================
 * Flash存储操作函数
 * ============================================================================ */

/**
 * @brief  向Flash写入多个16位数据
 * @param  startAddress 起始写入地址（必须是Flash地址范围内的有效地址）
 * @param  writeData 要写入的数据指针（16位数据数组）
 * @param  countToWrite 要写入的数据个数（16位数据个数）
 * @note   本函数实现了Flash的批量写入功能，支持跨扇区写入：
 *          1. 自动计算需要擦除的扇区数量和位置
 *          2. 在写入前自动擦除相关扇区
 *          3. 按半字（16位）方式写入数据
 *          4. 自动处理Flash的解锁和上锁
 *          5. 进行地址合法性检查
 *          注意：Flash写入前必须先擦除，擦除以扇区为单位（2KB）
 *          对于STM32F103V，Flash地址范围：0x08000000~0x0803FFFF
 * @retval HAL_StatusTypeDef 操作状态：HAL_OK=成功，HAL_ERROR=失败
 */
HAL_StatusTypeDef FLASH_WriteMoreData(uint32_t startAddress, uint16_t *writeData, uint16_t countToWrite)
{
    /* 计算去掉Flash基地址（0x08000000）后的实际偏移地址 */
    uint32_t offsetAddress = startAddress - FLASH_BASE;
    /* 计算扇区位置，对于 STM32F103V 为0~127 */
    uint32_t sectorPosition = offsetAddress / SECTOR_SIZE;
    /* 计算对应扇区的首地址 */
    uint32_t sectorStartAddress = sectorPosition * SECTOR_SIZE + FLASH_BASE;
    uint16_t Index;

    /* 计算起始地址在扇区内的偏移量 */
    uint32_t startAddressOffset = startAddress - sectorStartAddress;
    /* 计算总写入长度（字节数） */
    uint32_t Total_len = countToWrite * 2;
    uint32_t writeAddr = startAddress;
    /* 计算待擦除的扇区个数（考虑起始地址偏移） */
    uint32_t EraseSectorNum = (Total_len + startAddressOffset) / SECTOR_SIZE;
    
    HAL_StatusTypeDef status = HAL_OK;
    FLASH_EraseInitTypeDef EraseInitStruct;
    uint32_t SectorError = 0;
    
    /* 如果有余数，需要多擦除一个扇区 */
    if((Total_len + startAddressOffset) % SECTOR_SIZE)
        EraseSectorNum += 1;
  
    /* 地址合法性检查：起始地址必须在Flash范围内 */
    if(startAddress < FLASH_BASE || ((startAddress + Total_len) >= Flash_EndAddr))
    {
        return HAL_ERROR;     /* 非法地址 */
    }

    /* 扇区地址合法性检查 */
    if(sectorStartAddress < FLASH_BASE || (sectorStartAddress >= Flash_EndAddr))
    {
        return HAL_ERROR;     /* 非法地址 */
    }
  
    /* 解锁Flash写保护 */
    HAL_FLASH_Unlock();

    /* 检查是否需要跨扇区写入 */
    if((writeAddr + Total_len) >= (sectorStartAddress + SECTOR_SIZE))
    {
        /* 循环擦除需要写入的所有扇区 */
        for(Index = 0; Index < EraseSectorNum; Index++) 
        {
            EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;  /* 设置擦除类型为页擦除 */
            EraseInitStruct.PageAddress = sectorStartAddress;    /* 设置要擦除的扇区地址 */
            EraseInitStruct.NbPages = 1;                          /* 每次擦除1个扇区 */
            /* 执行扇区擦除操作 */
            status = HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError);
            if(status != HAL_OK)
            {
                HAL_FLASH_Lock();  /* 擦除失败，上锁Flash */
                return status;
            }
            /* 移动到下一个扇区 */
            sectorStartAddress += SECTOR_SIZE;
        }

        /* 循环写入所有数据（按半字方式写入） */
        for(Index = 0; Index < countToWrite; Index++)         
        {
            /* 按半字（16位）方式编程Flash */
            status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, startAddress + Index * 2, writeData[Index]);
            if(status != HAL_OK)
            {
                break;  /* 写入失败，退出循环 */
            }
        }
    }
    /* 上锁Flash写保护 */
    HAL_FLASH_Lock();
    return status;
}


