//
// Created by villuton on 17.09.2025.
//
#include <stdio.h>
#include "Main_Private.h"

#define STORAGE_DEVICE(VAR) env->storage.nvm.device.VAR
#define ADC(CH) env->adcs.tab[CH]
#define INDICATION(CH) env->indication.chanel[CH]
#define LOGGER &env->slog.logger
#define LOG_SIGN "Main_Processing"

/**
 * Установка пина зарядника по каналу
 * @param env
 * @param chanel
 * @param value
 */
void ChargerChanelSet(tMain *env, uint8_t chanel, bool value){
    GpioPinSet(&env->gpios.chrgEnPins.tab[chanel], value);
}

/**
 * Установка пина включения акб в цепь по каналу
 * @param env
 * @param chanel
 * @param value
 */
void BatteryChanelSet(tMain *env, uint8_t chanel, bool value){
    GpioPinSet(&env->gpios.batEnPins.tab[chanel], value);
}

/**
 * Процедура установки положения пинов,
 * в зависимости от того, идет сейчас проверка напряжения акб или нет
 * @param env
 * @param chanel
 * @param check
 */
void SetPinsModeCheck(tMain *env, uint8_t chanel, bool check){
    if(check == false){
        ChargerChanelSet(env,chanel,true);
        BatteryChanelSet(env,chanel,true);
    }
    else{
        ChargerChanelSet(env,chanel,false);
        BatteryChanelSet(env,chanel,true);
    }
}

/**
 * Процедура приведения данных АЦП к напряжению
 * С поправкой либо на делитель, либо на калибровочный коэффициент
 * @param env
 * @param chanel
 * @return
 */
#undef LOG_SIGN
#define LOG_SIGN "AdcToVoltage"
static float AdcToVoltage(tMain *env, uint8_t chanel){
    if(STORAGE_DEVICE(chanelCalibrationFactor[chanel]) != STORAGE_CALIBRATION_FACTOR_DEFAULT){
        /// Расчет через калибровочный параметр
        LoggerTraceStatic(LOGGER, LOG_SIGN, "Calculation via calibration parameter")
        return (float ) ADC(chanel) *
                STORAGE_DEVICE(chanelCalibrationFactor[chanel]);
    }
    /// Расчет через коэффициент делителя
    LoggerTraceStatic(LOGGER, LOG_SIGN, "Calculation using the divisor coefficient")
    return (float ) ADC(chanel) *
                    (STORAGE_V_ADC_THRESHOLD / STORAGE_ADC_THRESHOLD) *
                    STORAGE_DEVICE(dividerRatio);

}

/**
 * Процедура обработки переходов режимов
 * в зависимости от значений считанного напряжения
 * @param env
 * @param value
 * @param isCheck
 * @return
 */
static eIndicationMod AdcChanelModeProcessing(tMain *env,float value, bool isCheck){

    if(value <= STORAGE_DEVICE(voltageBatteryConnectThreshold)){
        LoggerTraceStatic(LOGGER, LOG_SIGN, "The voltage is lower Battery Connect Threshold")
        LoggerTraceStatic(LOGGER, LOG_SIGN, "Set mode STARTUP")
        return MOD_CH_STARTUP;
    }
    if(value <= STORAGE_DEVICE(voltageBatteryLoadedThreshold)){
        LoggerTraceStatic(LOGGER, LOG_SIGN, "The voltage is lower Battery Loader Threshold")
        LoggerTraceStatic(LOGGER, LOG_SIGN, "Set mode CHARGE")
        return MOD_CH_CHARGE;
    }
    if(value > STORAGE_DEVICE(voltageBatteryLoadedThreshold)){
        LoggerTraceStatic(LOGGER, LOG_SIGN, "The voltage is higher Battery Loader Threshold")
        if(isCheck != false){
            LoggerTraceStatic(LOGGER, LOG_SIGN, "Is check time")
            LoggerTraceStatic(LOGGER, LOG_SIGN, "Set mode OK")
            return MOD_CH_OK;
        } else{
            LoggerTraceStatic(LOGGER, LOG_SIGN, "Is not check time")
            LoggerTraceStatic(LOGGER, LOG_SIGN, "Set mode CHARGE")
            return MOD_CH_CHARGE;
        }
    }

    return MOD_CH_ERROR;
}

/**
 * Процедура Обработчика данным с АЦП, включения/отключения зарядки и выставление режимов индикации
 * @param env
 */
#undef LOG_SIGN
#define LOG_SIGN "Main_Processing"
void Main_Processing(tMain *env){
    ///Обновление таблицы данных каналов АЦП
    LoggerTraceStatic(LOGGER, LOG_SIGN, "Updating the ADC channel data table")
    Adcs_UpdateTab(&env->adcs);


    ///Проходимся в цикле по всем каналам
    for (int chanel = CHRG_Ch1; chanel < CHARGER_CH_NUM; chanel++) {
        env->processing.currentChanel = chanel;
        char msd_buff[30] = {0};
        sprintf(msd_buff,"Current Chanel: %d \n\r", chanel+1);
        LoggerCnTrace(LOGGER, LOG_SIGN, msd_buff, sizeof(msd_buff))
        switch (INDICATION(chanel)) {
            /**
             * В режиме стартапа предполагаем, что ожидаем подключения аккумулятора
             * Зарядник отключен, режим постоянной проверки
             */
            case MOD_CH_STARTUP:
                LoggerTraceStatic(LOGGER, LOG_SIGN, "Current mod STARTUP")

                SetPinsModeCheck(env,chanel,true);
                INDICATION(chanel) = AdcChanelModeProcessing(env,AdcToVoltage(env, chanel), true);
                /**
                 * В режиме зарядника возможен переход в любое из состояний, но переход в состояние "Заряжен"
                 * Возможен только при флаге check = true
                 */
            case MOD_CH_CHARGE:
                LoggerTraceStatic(LOGGER, LOG_SIGN, "Current mod CHARGE")

                SetPinsModeCheck(env,chanel,env->processing.check);
                INDICATION(chanel) = AdcChanelModeProcessing(env,AdcToVoltage(env, chanel), env->processing.check);
                /**
                 * Это режим состояния, говорящий, что АКБ заряжен
                 */
            case MOD_CH_OK:
                LoggerTraceStatic(LOGGER, LOG_SIGN, "Current mod OK")

                SetPinsModeCheck(env,chanel,true);
                INDICATION(chanel) = AdcChanelModeProcessing(env,AdcToVoltage(env, chanel), true);
                /**
                 * Режим ошибки, по факту сейчас не используется
                 */
            case MOD_CH_ERROR:
                LoggerTraceStatic(LOGGER, LOG_SIGN, "Current mod ERROR")

                ChargerChanelSet(env,chanel,false);
                BatteryChanelSet(env,chanel,false);

            default:
                break;
        }
    }
    /// Переустановка таймера и флага для отключения зарядника и проверки на заряд
    if(env->processing.timer < SystemGetMs()){
        LoggerTraceStatic(LOGGER, LOG_SIGN, "Timer update")
        env->processing.timer = SystemGetMs() + env->processing.check != false?
                                STORAGE_CHARGE_TIME :
                                STORAGE_VERIFICATION_TIME;
        env->processing.check = !env->processing.check;
    }
}
