/** ************************************************************************** * @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); }