- исправлены баги библиотеки memspi - добавлены модули для сохранения настреок в eeprom и flash (с равномерным износом) - надо тестить, проверять и рефакторить
381 lines
12 KiB
C
381 lines
12 KiB
C
/**
|
||
**************************************************************************
|
||
* @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->update_settings_flag = 1;
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
if(settings->update_settings_flag)
|
||
{
|
||
// if(GPIO_Read_Switch(&MZKT_DISCIN.err_24V))
|
||
// {
|
||
// printf_memspi_err("Power Err, cancel writing");
|
||
// settings->update_settings_flag = 0;
|
||
// update_start = 0;
|
||
// return;
|
||
// }
|
||
if(msDelayDone(1000, &update_request_tick))
|
||
{
|
||
update_start = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
msDelayStart(&update_request_tick);
|
||
update_start = 0;
|
||
}
|
||
|
||
|
||
if(update_start)
|
||
{
|
||
// Сбрасываем флаг обновления
|
||
settings->update_settings_flag = 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_CheckSettings(settings);
|
||
__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
|
||
|
||
if(MEMSPI_FLASH_Protection(settings->hmemspi, settings->start_adr, settings->settings_size, DISABLE, 1000) != HAL_OK)
|
||
{
|
||
settings->settings_error |= MEMORY_ERROR_WRITE;
|
||
return;
|
||
}
|
||
|
||
for(uint8_t i = 0; i < settings->setarr_count; i++)
|
||
{
|
||
|
||
WriteSettingsArrayToMem(settings, &settings->setarr[i]);
|
||
|
||
}
|
||
|
||
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_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);
|
||
}
|