#include "at32f403a_407.h"
#include "factors.h"
#include "common_config.h"
#include "sys_api.h"
#include "sys_hal.h"
#include "settings_api.h"
#include <stdio.h>

#if defined (MAI_12)

#undef DBG
#define DBG if(1)


factors_t ai_factors;


//
void factors_load(factors_t *factors)
{
    uint32_t load_crc;
    uint32_t new_crc;
    bool need_default = false;  
    
    factors_read_from_flash((uint8_t*)factors, sizeof(factors_t));
    
    // Считываем CRC из флеш памяти
    load_crc = (*(uint32_t*)CRC_FACTOR);
    
    // Рассчитываем CRC для структуры настроек
    new_crc = factors_get_crc(factors);
    
    // Если CRC не совпадают нужно прошивать дефолтные настройки
    if (load_crc != new_crc)
    {
        DBG printf("Bad factors sector CRC. Factors defaults restored.\r\n");
        need_default = true;
    }
    // CRC совпала, проверяем контрольное слово если слово не совпадает
	// то это значит, что поплыла структура нстроек, прошиваем дефолт */
    else if (factors->control_word != SETTINGS_CONTROL_WORD)
    {
        DBG printf("Bad factors control word. Factors defaults restored.\r\n");
        need_default = true;
    }
    
    // Прошиваем дефолтные настройки если нужно
    if (need_default) 
    {
        factros_set_default(factors);
        factors_save(factors);
    }

    //DBG sys_print(settings);
}


//
void factros_set_default(factors_t *factors) 
{
    for (int i = 0; i < AI_COMMON_NUMBER; i++)
    {
        factors->factor_b[i] = 0.0;
        factors->factor_k[i] = 1.0;
    }
    factors->control_word = SETTINGS_CONTROL_WORD;
}


//
bool factors_save(factors_t *factors)
{
    bool ret = false;
    
    xSemaphoreTake(flash_mutex, portMAX_DELAY);
    
    ret = factors_write_to_flash((uint8_t*)factors, sizeof(factors_t));
    
    xSemaphoreGive(flash_mutex);
    
    return ret;
}


//
bool factors_write_to_flash(uint8_t *data, uint32_t size)
{
    uint32_t baseAddress = CALIBRATION_FACTOR_SECTOR;
    uint32_t checkCrc = 0;
    uint32_t crc = factors_get_crc((factors_t*)data);
    flash_status_type status;
    uint8_t *ptr = data;
    
    flash_unlock();
    
    factors_sector_clear();
    
    for (uint32_t i = 0; i < size; i++)
        if ((status = flash_byte_program(baseAddress++, *data++)) != FLASH_OPERATE_DONE) {
            DBG printf("FLASH_ProgramByte error: status = %d\r\n", status);
            return false;
        }
    
    if ((status = flash_word_program((uint32_t)CRC_FACTOR, crc)) != FLASH_OPERATE_DONE) {
        DBG printf("FLASH_ProgramWord error: status = %d\r\n", status);
    }
    
    flash_lock();
    
    /* Считываем что записали */
    factors_read_from_flash(ptr, sizeof(factors_t));
    
    checkCrc = factors_get_crc((factors_t*)ptr);
    
    /* Проверяем  CRC того что было записано */
    if ((checkCrc != crc) || (status != FLASH_OPERATE_DONE)) {
        return false;
    }
    
    return true;
}


//
void factors_read_from_flash(uint8_t *data, uint32_t size)
{
    uint32_t baseAddress = CALIBRATION_FACTOR_SECTOR;
        
    for (uint32_t i = 0; i < size; i++)
        *data++ = (*(uint32_t*)baseAddress++);;
}


//
uint32_t factors_get_crc(factors_t *factors)
{
    crc_data_reset();
    return crc_block_calculate((uint32_t*)factors, sizeof(factors_t)/4 - 1);
}


// Очистить сектор системных настроек
void factors_sector_clear(void)
{
    flash_status_type status;
   
    if ((status = flash_sector_erase(CALIBRATION_FACTOR_SECTOR)) != FLASH_OPERATE_DONE) {
        DBG printf("Calibration factors. Erase sector error: %d\r\n", status);
    }
}

#endif