/********************************* (C) ROTEK *********************************** * @module settings_api * @file settings_api.c * @version 1.0.0 * @date XX.XX.XXXX * $brief Settings ******************************************************************************* * @history Version Author Comment * XX.XX.XXXX 1.0.0 Telenkov D.A. First release. ******************************************************************************* */ #include "stm32f4xx.h" #include "settings_api.h" #include "common_config.h" #include #include #include "tinystdio.h" #define DBG if(0) /** * @brief Флаг подтверждения новых сетевых параметров пользователем */ bool fConfirmWebParams = false; /** * @brief Общая структура настроек */ SETTINGS_t sSettings; /** * @brief Установить параметры обновления ПО по умолчанию */ void SETTINGS_SetBootParamsDef(void) { sSettings.bootParams.loadMode = 0; sSettings.bootParams.bootTry = 0; } /** * @brief Установить параметры сетевого подключения по умолчанию */ void SETTINGS_SetWebParamsDef(void) { strcpy(sSettings.sWebParams.ip, "192.168.0.254"); strcpy(sSettings.sWebParams.gate, "192.168.0.1"); strcpy(sSettings.sWebParams.mask, "255.255.255.0"); sSettings.sWebParams.dhcpEnable = 0; } /** * @brief Установить временные параметры сетевого подключения по умолчанию */ void SETTINGS_SetTempWebParamsDef(void) { strcpy(sSettings.sWebTempParams.ip, "192.168.0.254"); strcpy(sSettings.sWebTempParams.gate, "192.168.0.1"); strcpy(sSettings.sWebTempParams.mask, "255.255.255.0"); sSettings.sWebTempParams.dhcpEnable = 0; } /** * @brief Установить Информацию об устройстве по умолчанию */ void SETTINGS_SetInfoDef(void) { strcpy(sSettings.sInfo.productionData, "00.00.00 00:00"); strcpy(sSettings.sInfo.mac, DEVICE_MAC); strcpy(sSettings.sInfo.serialNumber, DEVICE_SERIAL); strcpy(sSettings.sInfo.comments, ""); } /** * @brief Сброс всех настроек в значения по умолчанию кроме сетевых настроек */ void SETTINGS_SetPartDefault(void) { SETTINGS_SetBootParamsDef(); SETTINGS_SetInfoDef(); sSettings.CritSecCRC = SETTINGS_GetCritSecCRC(); // sSettings.controlWorld = SETTINGS_CONTROL_WORD; } /** * @brief Сброс всех настроек в значения по умолчанию */ void SETTINGS_SetAllDefault(void) { SETTINGS_SetBootParamsDef(); SETTINGS_SetWebParamsDef(); SETTINGS_SetTempWebParamsDef(); SETTINGS_SetInfoDef(); sSettings.CritSecCRC = SETTINGS_GetCritSecCRC(); // sSettings.controlWorld = SETTINGS_CONTROL_WORD; } /** * @brief Установка настроек для отладки */ void SETTINGS_SetDefaultDebug(void) { SETTINGS_SetWebParamsDef(); SETTINGS_SetTempWebParamsDef(); SETTINGS_SetBootParamsDef(); //SETTINGS_SetInfoDef(); sSettings.CritSecCRC = SETTINGS_GetCritSecCRC(); // sSettings.controlWorld = SETTINGS_CONTROL_WORD; } /** * @brief Запись структуры настроек во flesh */ void SETTINGS_Save(void) { /* Calc critical section CRC and store to the settings structure */ sSettings.CritSecCRC = SETTINGS_GetCritSecCRC(); SETTINGS_WriteToFlash((uint8_t*)&sSettings, sizeof(sSettings)); } /** * @brief Загрузка структуры настроек из flesh */ void SETTINGS_Load(void) { SETTINGS_ReadFromFlash((uint8_t*)&sSettings, sizeof(sSettings)); /* Проверка CRC критической секции сектора настроек. * Если CRC не совпадает, скорее всего настройки отсутствуют, * прошиваем значения по умолчанию */ uint32_t crc = SETTINGS_GetCritSecCRC(); if (sSettings.CritSecCRC != crc) { printf("\n\rIAP: Bad critical settings sector CRC. Factory defaults restored.\n\r"); SETTINGS_SetAllDefault(); SETTINGS_Save(); } } /** * @brief */ void SETTINGS_WriteToFlash(uint8_t *data, uint32_t size) { uint32_t baseAddress = SETTINGS_SECTOR; uint32_t checkCrc = 0; uint32_t crc = SETTINGS_GetCRC(); bool fAlarm = 0; FLASH_Status status; for (uint8_t i = 0; i < 3; i++) { fAlarm = 0; FLASH_Unlock(); SETTINGS_EraseFlashSector(); for (uint32_t i = 0; i < size; i++) if ((status = FLASH_ProgramByte(baseAddress++, *data++)) != FLASH_COMPLETE) { DBG printf("FLASH_ProgramByte error: status = %d\r\n", status); break; } if ((status = FLASH_ProgramWord((uint32_t)CRC_ADDRESS, crc)) != FLASH_COMPLETE) { DBG printf("FLASH_ProgramWord error: status = %d\r\n", status); } FLASH_Lock(); /* Считываем что записали */ SETTINGS_ReadFromFlash((uint8_t*)&sSettings, sizeof(sSettings)); checkCrc = SETTINGS_GetCRC(); /* Проверяем CRC того что было записано */ if (checkCrc == crc) break; else fAlarm = 1; // Авария } /* Произошел сбой при записи - висим */ if (fAlarm) while (1) {}; } /** * @brief */ void SETTINGS_ReadFromFlash(uint8_t *data, uint32_t size) { uint32_t baseAddress = SETTINGS_SECTOR; for (uint32_t i = 0; i < size; i++) *data++ = (*(uint32_t*)baseAddress++);; } /** * @brief Очистка сектора настроек * @retval */ void SETTINGS_EraseFlashSector(void) { FLASH_Status status; if ((status = FLASH_EraseSector(FLASH_Sector_1, VoltageRange_3)) != FLASH_COMPLETE) { DBG printf("SETTINGS_EraseFlashSector error: status = %d/r/n", status); } } /** * @brief * @retval */ uint32_t SETTINGS_GetCRC(void) { CRC_ResetDR(); return CRC_CalcBlockCRC((uint32_t*)&sSettings, sizeof(sSettings)/4); } /** * @brief * @retval */ uint32_t SETTINGS_GetCritSecCRC(void) { CRC_ResetDR(); uint32_t critsec_len = (uint32_t)((uint8_t *)(&sSettings.CritSecCRC) - (uint8_t *)&sSettings) / 4; return CRC_CalcBlockCRC((uint32_t *)&sSettings, critsec_len); } /** * @brief Преобразует mac адрес строкового формата в массив uint8_t * @param mac - буфер для вывода mac адреса */ void SETTINGS_GetMac(uint8_t *mac) { char dummy[2]; char *macPtr = sSettings.sInfo.mac; for (uint8_t i = 0; i < 6; i++) { strncpy(dummy, macPtr+i*3, 2); mac[i] = (uint8_t)strtol(dummy, NULL, 16); } } /********************************* (C) ROTEK **********************************/