/********************************* (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" #ifndef BT6702_SERVICE #include "snmp_api.h" #include "log.h" #endif #include "sys_api.h" #include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include "main.h" #include "parameters.h" #include "mbedtls/certs.h" #include #include #ifdef PRINTF_STDLIB #include #endif #ifdef PRINTF_CUSTOM #include "tinystdio.h" #endif //#define DBG if(0) #if defined ( __ICCARM__ ) #define DEVICE_MAC "00-00-00-00-00-03" #endif const float UPSPowerMass[] = {1000, 1500, 2000, 3000, 6000, 10000}; const float UPSEfficiencyFactorMass[] = {0.83, 0.87, 0.87, 0.88, 0.9, 0.91}; SemaphoreHandle_t flash_mutex; /** * @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) { SYS_t *sSys = NULL; sSys = pvPortMalloc(sizeof(*sSys)); if (sSys) { SYS_Load(sSys); strcpy(sSettings.sInfo.mac, sSys->mac); strcpy(sSettings.sInfo.serialNumber, sSys->serial); strcpy(sSettings.sInfo.productionData, sSys->proddate); strcpy(sSettings.sFlags.testState, sSys->testState); vPortFree(sSys); } else { strcpy(sSettings.sInfo.productionData, "09.07.2017"); strcpy(sSettings.sInfo.mac, DEVICE_MAC); strcpy(sSettings.sInfo.serialNumber, DEVICE_SERIAL); strcpy(sSettings.sFlags.testState, "T2OK"); } strcpy(sSettings.sInfo.comments, ""); } /** * @brief Установить флаги по умолчанию */ void SETTINGS_SetFlagsDef(void) { sSettings.sFlags.netsettingsChanged = false; } /** * @brief Сброс всех настроек в значения по умолчанию кроме сетевых настроек */ void SETTINGS_SetPartDefault(void) { SETTINGS_SetBootParamsDef(); SETTINGS_SetFlagsDef(); #define XSETTING(type, name, setter, type_reset) if (type_reset == ALL_DEFAULT) setter(); SETTINGS_TABLE #undef XSETTING sSettings.CritSecCRC = SETTINGS_GetCritSecCRC(); sSettings.controlWorld = SETTINGS_CONTROL_WORD; } /** * @brief Сброс всех настроек в значения по умолчанию */ void SETTINGS_SetAllDefault(void) { SETTINGS_SetBootParamsDef(); SETTINGS_SetWebParamsDef(); SETTINGS_SetTempWebParamsDef(); SETTINGS_SetInfoDef(); SETTINGS_SetFlagsDef(); SETTINGS_SetUPSSerialSettingsDef(); #define XSETTING(type, name, setter, type_reset) setter(); SETTINGS_TABLE #undef XSETTING sSettings.CritSecCRC = SETTINGS_GetCritSecCRC(); sSettings.controlWorld = SETTINGS_CONTROL_WORD; } /** * @brief Установка настроек для отладки */ void SETTINGS_SetDefaultDebug(void) { SETTINGS_SetWebParamsDef(); SETTINGS_SetTempWebParamsDef(); SETTINGS_SetBootParamsDef(); SETTINGS_SetFlagsDef(); #define XSETTING(type, name, setter, type_reset) if (type_reset != PART_DEFAULT_2) setter(); SETTINGS_TABLE #undef XSETTING sSettings.CritSecCRC = SETTINGS_GetCritSecCRC(); sSettings.controlWorld = SETTINGS_CONTROL_WORD; } /** * @brief Запись структуры настроек во flesh */ void SETTINGS_Save(void) { xSemaphoreTake(flash_mutex, portMAX_DELAY); /* Calc critical section CRC and store to the settings structure */ sSettings.CritSecCRC = SETTINGS_GetCritSecCRC(); SETTINGS_WriteToFlash((uint8_t*)&sSettings, sizeof(sSettings)); xSemaphoreGive(flash_mutex); } /** * @brief Загрузка структуры настроек из flesh */ void SETTINGS_Load(void) { uint32_t loadCRC; // CRC из flash uint32_t newCRC; // CRC загруженной структуры настроек bool need_default = false; WEB_PARAMS_t sWebParamsBackup; BOOT_PARAMS_t bootParamsBackup; SETTINGS_ReadFromFlash((uint8_t*)&sSettings, sizeof(sSettings)); /* Считываем CRC из флеш памяти */ loadCRC = (*(uint32_t*)CRC_ADDRESS); /* Рассчитываем CRC для структуры настроек */ newCRC = SETTINGS_GetCRC(); if (loadCRC != newCRC) { /* SETTINGS_SetAllDefault(); SETTINGS_Save();*/ need_default = true; } /* CRC совпала, проверяем контрольное слово если слово не совпадает то это значит, что поплыла структура нстроек, прошиваем дефолт */ else if (sSettings.controlWorld != SETTINGS_CONTROL_WORD) { need_default = true; } /* Прошиваем дефолтные настройки если нужно */ if (need_default) { /* Бэкапим сетевые параметры загрузчика */ memcpy(&sWebParamsBackup, &sSettings.sWebParams, sizeof(sWebParamsBackup)); /* Бэкапим флаги загрузчика */ memcpy(&bootParamsBackup, &sSettings.bootParams, sizeof(bootParamsBackup)); loadCRC = sSettings.CritSecCRC; newCRC = SETTINGS_GetCritSecCRC(); SETTINGS_SetAllDefault(); if (loadCRC == newCRC) { /* Применяем флаги загрузчика */ memcpy(&sSettings.bootParams, &bootParamsBackup, sizeof(sSettings.bootParams)); /* Применяем сетевые параметры загрузчика */ memcpy(&sSettings.sWebParams, &sWebParamsBackup, sizeof(sSettings.sWebParams)); } 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 - 1); } /** * @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 Сброс флага boottry в регистре RTC */ void SETTINGS_ResetBootTry(void) { uint8_t bootTry = RTC_ReadBackupRegister(RTC_BKP_DR2); if (bootTry > 0 ) { bootTry = 0; RTC_WriteBackupRegister(RTC_BKP_DR2, 0); /* Check FW update flag */ if (RTC_ReadBackupRegister(RTC_BKP_DR3)) { /* Отправка трапа об успешном обновлении ПО */ #ifndef BT6702_SERVICE SNMP_SendUserTrap(FW_VERSION_UPDATED); log_event_data(LOG_UPDATE_SOFT, "Успешно"); #endif /* Clear FW update flag */ RTC_WriteBackupRegister(RTC_BKP_DR3, 0); } } /* if (sSettings.bootParams.bootTry != 0) { sSettings.bootParams.bootTry = 0; // Отправка трапа об успешном обновлении ПО SNMP_SendUserTrap(FW_VERSION_UPDATED); //taskENTER_CRITICAL(); SETTINGS_Save(); //taskEXIT_CRITICAL(); } */ } /** * @brief Преобразует mac адрес строкового формата в массив uint8_t * @param mac - буфер для вывода mac адреса */ void SETTINGS_GetMac(uint8_t *mac) { char dummy[2]; char *macPtr = sSettings.sInfo.mac; #if defined ( __ICCARM__ ) macPtr = DEVICE_MAC; #endif for (uint8_t i = 0; i < 6; i++) { strncpy(dummy, macPtr+i*3, 2); mac[i] = (uint8_t)strtol(dummy, NULL, 16); } } /** * @brief Установить дату производства */ void SETTINGS_SetProDate(char *proDate, uint8_t len) { SYS_t *sSys = NULL; sSys = pvPortMalloc(sizeof(*sSys)); if (sSys) { SYS_Load(sSys); strcpy(sSys->proddate, proDate); SYS_Save(sSys); memset(sSettings.sInfo.productionData, 0, 40); memcpy(sSettings.sInfo.productionData, proDate, len); vPortFree(sSys); SETTINGS_Save(); } } /** * @brief Установить статус тестирования "T2OK" */ void SETTINGS_SetT2OK(void) { SYS_t *sSys = NULL; sSys = pvPortMalloc(sizeof(*sSys)); if (sSys) { SYS_Load(sSys); memset(sSettings.sFlags.testState, 0, 16); memcpy(sSettings.sFlags.testState, "T2OK", 4); strcpy(sSys->testState, sSettings.sFlags.testState); SYS_Save(sSys); vPortFree(sSys); SETTINGS_Save(); } } /** * @brief Включить DHCP */ void SETTINGS_SetDHCPOn(void) { sSettings.sWebParams.dhcpEnable = 1; } void init_settings(void) { flash_mutex = xSemaphoreCreateMutex(); } /********************************* (C) ROTEK **********************************/