Files
STM32_MemorySPI/Src/set_to_mem.c

387 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
**************************************************************************
* @file set_to_mem.c
* @brief Модуль для записи в память настроек.
*************************************************************************/
#include "set_to_mem.h"
/**
* @brief Инициализация одного массива настроек для хранения в памяти.
*
* @param array Указатель на структуру для записи настроек.
* @param pRealArray Указатель на реальные массива настроек.
* @param startadr Указатель на начальный адрес в памяти.
* @param sizeofarray Размер массива.
* @details Функция используется при @ref SETTINGS_USE_SETTINGS_FROM_POINTER
*/
HAL_StatusTypeDef Settings_AddArray(SettingsTypeDef *settings, uint8_t *pRealArray, uint32_t *startadr, uint32_t sizeofarray)
{
if(!settings || !pRealArray || !startadr || !sizeofarray)
return HAL_ERROR;
if(settings->setarr_count >= SETTINGS_MAX_ARRAYS)
return HAL_ERROR;
SettingArrayTypeDef *array = &settings->setarr[settings->setarr_count];
array->adr = *startadr; // Устанавливаем адрес начала массива настроек
array->length = sizeofarray; // Устанавливаем размер массива настроек
array->real_ptr = pRealArray;
#ifdef SETTINGS_USE_SETTINGS_FROM_POINTER
array->mem_ptr = pRealArray;
#else
if(settings->buffer == NULL)
{
settings->buffer = malloc(sizeofarray);
if(!settings->buffer)
return HAL_ERROR;
array->mem_ptr = settings->buffer;
settings->settings_size = sizeofarray;
}
else
{
// расширяем буфер под новый массив
uint8_t *newbuf = realloc(settings->buffer, settings->settings_size + sizeofarray);
if(!newbuf)
return HAL_ERROR;
settings->buffer = newbuf;
array->mem_ptr = settings->buffer + settings->settings_size;
settings->settings_size += sizeofarray;
}
#endif
*startadr += array->length; // Смещаем начальный адрес настроек
settings->setarr_count++;
return HAL_OK;
}
HAL_StatusTypeDef Settings_Init(SettingsTypeDef *settings, SPI_HandleTypeDef *hspi, uint32_t adr)
{
if(!settings)
return HAL_ERROR;
settings->start_adr = adr;
// settings->setarr_count = 0;
settings->settings_error = 0;
settings->hmemspi = &memory_spi;
MEMSPI_Base_Init(settings->hmemspi, hspi);
#ifdef SETTINGS_USE_WEAR_LEVELING_FLASH
if(MEMSPI_FLASH_Protection(&memory_spi, 0, 0x11000, 1000, 1) != HAL_OK)
{
return HAL_ERROR;
}
ParamsFlash_HandleInit(&settings->flash_handle, 0, 1, settings->settings_size);
if(MEMSPI_FLASH_Protection(&memory_spi, 0, 0x11000, 1000, 1) != HAL_OK)
{
return HAL_ERROR;
}
#endif
return HAL_OK;
}
/**
* @brief Запись настроек в память.
*
* @param settings Указатель на хендл для настроек.
* @details Записывает настройки в память, если установлен флаг обновления.
* Можно включить защиту @ref SETTINGS_MEMORY_PROTECT_ENABLE : добавляет защиту памяти перед записью и снимает её после.
*/
void Settings_WriteSettings(SettingsTypeDef *settings)
{
if(!settings)
return;
static int update_start = 0;
static uint32_t update_request_tick = 0;
HAL_StatusTypeDef res = HAL_OK;
#ifdef SETTINGS_USE_SETTINGS_FROM_BUFFER
// Сравниваем текущие настройки с буфером
for(int i = 0; i < settings->setarr_count; i++)
{
if(memcmp(settings->setarr[i].mem_ptr,
settings->setarr[i].real_ptr,
settings->setarr[i].length) != 0)
{
settings->f.settings_need_to_update = 1;
break;
}
}
#endif
// if(settings->f.settings_need_to_update)
// {
//// if(GPIO_Read_Switch(&MZKT_DISCIN.err_24V))
//// {
//// printf_memspi_err("Power Err, cancel writing");
//// settings->f.settings_need_to_update = 0;
//// update_start = 0;
//// return;
//// }
// if(msDelayDone(1000, &update_request_tick))
// {
// update_start = 1;
// }
// }
// else
// {
// msDelayStart(&update_request_tick);
// update_start = 0;
// }
settings->f.settings_is_updated = 0;
if(settings->f.settings_need_to_update)
{
// Сбрасываем флаг обновления
settings->f.settings_need_to_update = 0;
update_start = 0;
#ifdef SETTINGS_USE_SETTINGS_FROM_BUFFER
// Обновляем буфер новыми настройками
for(uint8_t i = 0; i < settings->setarr_count; i++)
{
memcpy( settings->setarr[i].mem_ptr,
settings->setarr[i].real_ptr,
settings->setarr[i].length);
}
#endif
// Записываем настройки в память
WriteSettingsToMem(settings);
Settings_ReadSettings(settings);
Settings_CheckSettings(settings);
settings->f.settings_is_updated = 1;
__enable_irq();
}
}
/**
* @brief Чтение настроек из памяти.
*
* @param settings Указатель на хендл для настроек.
* @details Включает:
* - Чтение настроек из памяти (`ReadSettingsFromMem`).
* - Обновление буфера, если используется @ref SETTINGS_USE_SETTINGS_FROM_BUFFER.
*/
void Settings_ReadSettings(SettingsTypeDef *settings)
{
if(!settings)
return;
__disable_irq();
ReadSettingsFromMem(settings);
#ifdef SETTINGS_USE_SETTINGS_FROM_BUFFER
for(uint8_t i = 0; i < settings->setarr_count; i++)
{
memcpy(settings->setarr[i].real_ptr,
settings->setarr[i].mem_ptr,
settings->setarr[i].length);
}
#endif
__enable_irq();
Settings_CheckSettings(settings);
}
/**
* @brief Проверить настройки на валидность.
*
* @param settings Указатель на хендл для настроек.
* @details Проверяет не пустые ли настройки. Если пустые - выставялет флаг ошибки.
*/
void Settings_CheckSettings(SettingsTypeDef *settings)
{
if(!settings)
return;
uint32_t total_size = 0;
uint32_t ff_cnt = 0;
for(uint8_t i = 0; i < settings->setarr_count; i++)
{
uint8_t *ptr = settings->setarr[i].mem_ptr;
uint32_t size = settings->setarr[i].length;
total_size += size;
for(uint32_t j = 0; j < size; j++)
{
if(ptr[j] == 0xFF)
ff_cnt++;
}
}
if(total_size && ff_cnt > total_size * 0.8)
settings->settings_error |= MEMORY_ERROR_EMPTY;
else
settings->settings_error &= ~MEMORY_ERROR_EMPTY;
printf_memspi("Zero Bytes: %u/%u", ff_cnt, total_size);
}
/**
* @brief Записи настроек в память в зависимости от конфигурации.
*
* @param settings Указатель на хендл для настроек.
* @details Реализация зависит от конфигурации:
* - @ref SETTINGS_USE_SETTINGS_FROM_POINTER : запись по отдельным указателям на различные массивы настроек.
* - @ref SETTINGS_USE_SETTINGS_FROM_BUFFER : запись всего буфера настроек целиком.
*/
void WriteSettingsToMem(SettingsTypeDef *settings)
{
HAL_StatusTypeDef res = HAL_OK;
#ifdef SETTINGS_USE_WEAR_LEVELING_FLASH
if(MEMSPI_FLASH_Protection(settings->hmemspi, 0, 0x11000, DISABLE, 1000) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
return;
}
if(ParamsFlash_WriteBlock(&settings->flash_handle, PARAMS_LAST_BLOCK,
(uint16_t *)settings->buffer,
settings->settings_size) < 0)
{
res = HAL_ERROR;
}
if(MEMSPI_FLASH_Protection(settings->hmemspi, 0, 0x11000, ENABLE, 1000) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
}
#else //SETTINGS_USE_WEAR_LEVELING_FLASH
#ifndef SETTINGS_USE_MEMORY_EEPROM
if(MEMSPI_FLASH_Protection(settings->hmemspi, settings->start_adr, settings->settings_size, DISABLE, 1000) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
return;
}
#endif //SETTINGS_USE_MEMORY_EEPROM
for(uint8_t i = 0; i < settings->setarr_count; i++)
{
WriteSettingsArrayToMem(settings, &settings->setarr[i]);
}
#ifndef SETTINGS_USE_MEMORY_EEPROM
if(MEMSPI_FLASH_Protection(settings->hmemspi, settings->start_adr, settings->settings_size, DISABLE, 1000) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
return;
}
#endif //SETTINGS_USE_MEMORY_EEPROM
#endif //SETTINGS_USE_WEAR_LEVELING_FLASH
if(res != HAL_OK)
{
printf_memspi_err("Write Error: %u", res);
settings->settings_error |= MEMORY_ERROR_WRITE;
}
else
{
printf_memspi("Write Ok");
settings->settings_error &= ~MEMORY_ERROR_WRITE;
}
}
/**
* @brief Читает настройки из памяти в зависимости от конфигурации.
*
* @param settings Указатель на хендл для настроек.
* @details Реализация зависит от конфигурации:
* - @ref SETTINGS_USE_SETTINGS_FROM_POINTER : чтение по отдельным указателям на различные массивы настроек.
* - @ref SETTINGS_USE_SETTINGS_FROM_BUFFER : чтение всего буфера настроек целиком.
*/
void ReadSettingsFromMem(SettingsTypeDef *settings)
{
HAL_StatusTypeDef res = HAL_OK;
#ifdef SETTINGS_USE_WEAR_LEVELING_FLASH
if(ParamsFlash_ReadBlock(&settings->flash_handle, PARAMS_LAST_BLOCK,
(uint16_t *)settings->buffer,
settings->settings_size, NULL) < 0)
{
res = HAL_ERROR;
}
#else //SETTINGS_USE_WEAR_LEVELING_FLASH
for(uint8_t i = 0; i < settings->setarr_count; i++)
{
ReadSettingsArrayFromMem(settings, &settings->setarr[i]);
}
#endif //SETTINGS_USE_WEAR_LEVELING_FLASH
if(res != HAL_OK)
{
printf_memspi_err("Read Error: %u", res);
}
else
{
printf_memspi("Read Ok");
}
}
/**
* @brief Записывает массив настроек через указатель в память.
*
* @param settings Указатель на хендл для настроек.
* @param settingarr Указатель на структуру для записи массива настроек.
* @details Функция используется при @ref SETTINGS_USE_SETTINGS_FROM_POINTER
*/
void WriteSettingsArrayToMem(SettingsTypeDef *settings, SettingArrayTypeDef *settingarr)
{
#ifndef SETTINGS_USE_MEMORY_EEPROM
MEMSPI_WriteInitTypeDef writeinit;
writeinit.Data_Address = settingarr->adr;
writeinit.Data_Size = settingarr->length;
writeinit.Sector_Address = settings->start_adr;
writeinit.Sector_Size = settings->settings_size;
writeinit.fSavePrevoisData = 1;
writeinit.pDataPtr = settingarr->mem_ptr;
if(MEMSPI_FLASH_Write(settings->hmemspi, &writeinit, 1000, 1) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
return;
}
#else
if(MEMSPI_EEPROM_Write(settings->hmemspi, settingarr->adr, settingarr->mem_ptr, settingarr->length, 1000, 1) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
return;
}
#endif
}
/**
* @brief Читает массив настроек через указатель в память.
*
* @param settings Указатель на хендл для настроек.
* @param settingarr Указатель на структуру для записи массива настроек.
* @details Функция используется при @ref SETTINGS_USE_SETTINGS_FROM_POINTER
*/
void ReadSettingsArrayFromMem(SettingsTypeDef *settings, SettingArrayTypeDef *settingarr)
{
MEMSPI_Read_Memory(settings->hmemspi, settingarr->adr, settingarr->mem_ptr, settingarr->length, 1000);
}