#include "at32f403a_407.h"
#include "modbus_params.h"
#include "modbus_dio_params.h"
#include "modbus_ai_params.h"
#include "modbus_ao_params.h"
#include "io.h"
#include "uptime.h"
#include "rtc.h"
#include "digital_input.h"
#include "digital_output.h"
#include "log.h"
#include "log_dio.h"
#include "log_ai.h"
#include "settings_api.h"
#include "common_config.h"
#include "swap.h"
#include "common_gpio.h"
#include "monitoring.h"
#include "rtc_battery.h"
#include "soft_wdt.h"
#include <string.h>


mb_param_t mb_param[MB_PARAM_MAX];

uint32_t rtc_sinhro;

// Пароль для установки системных настроек
uint16_t psw;   
bool psw_ok = false;
uint8_t fw_version[8];
uint16_t save_sys_cmd = 0;  // Команда сохранения системных настроек
uint16_t system_cmd = 0;	// Команда управления контроллером
uint64_t value_64 = 0;
uint8_t value_8 = 0;
uint8_t arch_channel = 0;

void get_time(uint8_t* buf, uint8_t size);
void get_din_mode(uint8_t* buf, uint8_t size);

void get_log_entries_number(uint8_t* buf, uint8_t size);

void get_arch_ch_1(uint8_t* buf, uint8_t size);
void get_arch_ch_2(uint8_t* buf, uint8_t size);
void get_arch_ch_3(uint8_t* buf, uint8_t size);
void get_arch_ch_4(uint8_t* buf, uint8_t size);
void get_arch_ch_5(uint8_t* buf, uint8_t size);
void get_arch_ch_6(uint8_t* buf, uint8_t size);
void get_arch_ch_7(uint8_t* buf, uint8_t size);
void get_arch_ch_8(uint8_t* buf, uint8_t size);
void get_arch_ch_9(uint8_t* buf, uint8_t size);
void get_arch_ch_10(uint8_t* buf, uint8_t size);
void get_arch_ch_11(uint8_t* buf, uint8_t size);
void get_arch_ch_12(uint8_t* buf, uint8_t size);

void (*get_ch_entries_number[12])(uint8_t* buf, uint8_t size) = {
    get_arch_ch_1, get_arch_ch_2, get_arch_ch_3, get_arch_ch_4,
    get_arch_ch_5, get_arch_ch_6, get_arch_ch_7, get_arch_ch_8,
    get_arch_ch_9, get_arch_ch_10, get_arch_ch_11, get_arch_ch_12
};


void get_rtc(uint8_t* buf, uint8_t size);



//
void mb_init_params(void)
{
    uint16_t index = 0;
    uint16_t addr = 0;

#if defined (MDIO_88)
    // 61 параметр
    index = mb_init_dio_params(0);
#endif 
    
#if defined (MAI_12)
    index = mb_init_ai_params(0);
#endif    
    
#if defined (MAO_4)
    index = mb_init_ao_params(0);
#endif    
    
    // ---------------------------------------------------------------------- //
	//	Управление контроллером. Системные параметры.
	// ---------------------------------------------------------------------- //
    
    // Управление контроллером
    mb_param[index].reg = 0x0800;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&system_cmd; // 
	mb_param[index].set = mb_control;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // uptime
    mb_param[index].reg = 0x0801;
	mb_param[index].size = 2;
	mb_param[index].param = (uint8_t*)&uptime; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // RTC
    mb_param[index].reg = 0x0803;
	mb_param[index].size = 4;
	mb_param[index].param = (uint8_t*)&value_64; // 
	mb_param[index].set = mb_set_rtc;
    mb_param[index].get = get_rtc;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Напряжение на батарее RTC
    mb_param[index].reg = 0x0807;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&bat_voltage; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Состояние модуля
    mb_param[index].reg = 0x0809;
	mb_param[index].size = 2;
	mb_param[index].param = (uint8_t*)&mon_state; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Пользовательская информация. Текстовая строка.
    mb_param[index].reg = 0x080B;
	mb_param[index].size = 16;
	mb_param[index].param = (uint8_t*)&settings.info; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Безопасный режим работы
    mb_param[index].reg = 0x081B;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&settings.save_mode; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Время до перехода в безопасный режим работы
    mb_param[index].reg = 0x081C;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&settings.save_delay; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // ---------------------------------------------------------------------- //
    // Журналы/рахивы
    // ---------------------------------------------------------------------- //
    
    // Емкость журнала (максимальная)
    mb_param[index].reg = 0x0900;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&log_entries_capacity; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Текущее количество записей в журнале
    mb_param[index].reg = 0x0901;
	mb_param[index].size = 1;
	mb_param[index].param = NULL; // 
	mb_param[index].set = NULL;
    mb_param[index].get = get_log_entries_number;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Емкость архива (максимальная)
    mb_param[index].reg = 0x0902;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&archive_entries_capacity; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
#if defined (MDIO_88) || (MAI_12)    
    uint8_t channel_number = log_get_arch_channel_number();
    
    // Текущее количество записей в архиве по каждому каналу
    addr = 0x0903;
    for (int i = 0; i < channel_number; i++)
    {
        mb_param[index].reg = addr;
        mb_param[index].size = 1;
        mb_param[index].param = NULL;
        mb_param[index].set = NULL;
        mb_param[index].get = get_ch_entries_number[i];
        mb_param[index].check_handler = mb_check_dummy;
        
        addr++;
        index++;      
    }  
    
    // Период архива. 
    addr = 0x090F;
    for (int i = 0; i < channel_number; i++)
    {
        mb_param[index].reg = addr;
        mb_param[index].size = 1;
        mb_param[index].param = (uint8_t*)&settings.period_archive[i];  // Счетчик ипульсов
        mb_param[index].set = NULL;
        mb_param[index].get = NULL;
        mb_param[index].check_handler = mb_check_archiv_per;
        
        addr++;
        index++;
    }
#endif    
	// ---------------------------------------------------------------------- //
	//	Производственные параметры
	// ---------------------------------------------------------------------- //

    // Код модели (только чтение). Определяется прошивкой.
    mb_param[index].reg = 0x0080;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&model_code; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Ревизия платы (только чтение). Резисторы на плате.
    mb_param[index].reg = 0x0081;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&board_rev; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
        
    // Дата производства Unix формат (чтение/запись по паролю)
    mb_param[index].reg = 0x0082;
	mb_param[index].size = 2;
	mb_param[index].param = (uint8_t*)&temp_sys_settings.prod_date; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;

    // Серийный номер (чтение/запись по паролю).
    mb_param[index].reg = 0x0084;
	mb_param[index].size = 2;
	mb_param[index].param = (uint8_t*)&temp_sys_settings.sn; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Версия ПО (только чтение).
    memcpy(&fw_version, FW_VERSION, 8);
    mb_param[index].reg = 0x0086;
	mb_param[index].size = 4;
	mb_param[index].param = (uint8_t*)&fw_version; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Статус тестирования (чтение/запись по паролю).
    mb_param[index].reg = 0x008A;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&temp_sys_settings.test_state; // 
	mb_param[index].set = NULL;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Пароль
    mb_param[index].reg = 0x0090;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&psw; // 
	mb_param[index].set = mb_password;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
    
    // Команда на сохранение системных настроек
    mb_param[index].reg = 0x0091;
	mb_param[index].size = 1;
	mb_param[index].param = (uint8_t*)&save_sys_cmd; // 
	mb_param[index].set = mb_sys_settings_save;
    mb_param[index].get = NULL;
    mb_param[index].check_handler = mb_check_dummy;
    
    index++;
}


// Возвращает размер параметра в регистрах
bool mb_find_param(uint16_t reg, uint16_t *index, uint16_t *size)
{
	for (uint16_t i = 0; i < MB_PARAM_MAX; i++)
	{
		if (mb_param[i].reg == reg)
		{
			*index = i;
			*size = mb_param[i].size;
			return true;
		}
	}
	return false;
}


//
mb_delay_action_t mb_set_param(uint8_t *buf, uint16_t index)
{
	uint8_t *ptr = mb_param[index].param;

    // Если параметр только для чтения
    if (mb_param[index].check_handler == NULL)
        return MB_NO_ACTION;
    
	for (uint16_t i = 0; i < 2*mb_param[index].size; i++)
	{
		*ptr = buf[2*mb_param[index].size - 1 - i];
		ptr++;
	}
  
/*    
    if (mb_param[index].check_handler != NULL)
        mb_param[index].check_handler();
*/    
    
    mb_param[index].check_handler();
    
    if (mb_param[index].set != NULL)
        return mb_param[index].set();
    else
        return MB_NO_ACTION;
    
/*    
    if (mb_param[index].f_activity)
        return mb_param[index].set_handler();
    else
        return MB_NO_ACTION;
*/    
}


//
void mb_get_param(uint8_t *buf, uint16_t index)
{
    uint8_t *ptr;
	
    if (mb_param[index].get != NULL) {
        mb_param[index].get(buf, mb_param[index].size);
        return;
    }

    ptr = mb_param[index].param + 2*mb_param[index].size - 1;

	for (uint16_t i = 0; i < 2*mb_param[index].size; i++)
	{
		*buf = *ptr;
		buf++;
		ptr--;
	}
}





// -------------------------------------------------------------------------- //
//                          Чтение параметров
// -------------------------------------------------------------------------- //

#if 0
void get_time(uint8_t* buf, uint8_t size)
{
    uint32_t rtc_unix = RTC_GetUnixTime();
    uint8_t *ptr = (uint8_t*)&rtc_unix + 2*size - 1;

    for (uint16_t i = 0; i < 2*size; i++)
	{
		*buf = *ptr;
		buf++;
		ptr--;
	}
}
#endif



//
void get_din_mode(uint8_t* buf, uint8_t size)
{
    
}

//
void get_log_entries_number(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
    
    capacity = swap_uint16(log_capacity());
    memcpy(buf, &capacity, 2);
    //buf = (uint8_t*)&capacity;
}

//
void get_arch_ch_1(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(0));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_2(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(1));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_3(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(2));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_4(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(3));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_5(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(4));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_6(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(5));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_7(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(6));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_8(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(7));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_9(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(8));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_10(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(9));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_11(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(10));
    memcpy(buf, &capacity, 2);
}

//
void get_arch_ch_12(uint8_t* buf, uint8_t size)
{
    static uint16_t capacity;
      
    capacity = swap_uint16(log_arch_capacity(11));
    memcpy(buf, &capacity, 2);
}

//
void get_rtc(uint8_t* buf, uint8_t size)
{
    uint64_t rtc = swap_uint64(rtc_get_ms());
        
    memcpy(buf, &rtc, 8);
}


// -------------------------------------------------------------------------- //
//                          Установка параметров
// -------------------------------------------------------------------------- //

//
mb_delay_action_t mb_set_time(void)
{
    TM_RTC_SetDataTimeUnix(rtc_sinhro);
    
    return MB_NO_ACTION;
}

//
mb_delay_action_t mb_password(void)
{
    if (psw != MB_PASSWORD)
        return MB_PAS_ERR;
    else {
        if (psw_ok == false) {
            psw_ok = true;
            return MB_PAS_OK;
        }
        else
            return MB_NO_ACTION;
    }
}

//
mb_delay_action_t mb_sys_settings_save(void)
{
    if (save_sys_cmd == 1)
        return MB_SAVE_SYS_SETTINGS;
    else
        return MB_NO_ACTION;
}

//
mb_delay_action_t mb_control(void)
{
    if (system_cmd == MB_COM_SETTINGS_SAVE)
        return MB_SAVE_SETTINGS;
    else if (system_cmd == MB_COM_LOG_CLEAR)
        return MB_LOG_CLEAR;
    else if ((system_cmd >= (uint8_t)MB_COM_ARCH_CLEAR_1) && (system_cmd <= (uint8_t)MB_COM_ARCH_CLEAR_8)) {
        arch_channel = system_cmd;
        return MB_ARCHIVE_CLEAR;
    }
    else if (system_cmd == MB_COM_STOP_WDT)
        soft_wdt_dtop(true);
      
    return MB_NO_ACTION;
    
#if 0
    if (system_cmd == 1)
        return MB_SAVE_SETTINGS;
    else if (system_cmd == 2)
        return MB_DEF_SETTINGS;
    else if (system_cmd == 3)
        return MB_RESET;
    else if (system_cmd == 4)
        return MB_PART_DEF_SETTINGS;

    return MB_NO_ACTION;
#endif    
}

//
mb_delay_action_t mb_set_rtc(void)
{
    float delta;
    uint64_t now = rtc_get_ms();

    if (now >= value_64)
        delta = (float)(now - value_64);
    else
        delta = (float)(value_64 - now);
    
    
    rtc_set_in_ms((uint32_t)(value_64/1000));
    
    // -------------------------------------------------------------------------- //
    // EVENT. Перевод времени.
    log_add_entry(LOG_CLOCK_CHANGE, LOG_EVENT_STATE_OK, 0, delta);
    
    
    return MB_NO_ACTION;
}

// -------------------------------------------------------------------------- //
//                      Проверка параметров                                   //
// -------------------------------------------------------------------------- //

//
void mb_check_dummy(void)
{
}

//
void mb_check_archiv_per(void)
{
#if defined (MDIO_88) || (MAI_12)   
    uint8_t channel_number = log_get_arch_channel_number();
  
    for (uint8_t i = 0; i < channel_number; i++)
    {
        if (settings.period_archive[i] > (uint16_t)MAX_ARCHIVE_PERIOD)
            settings.period_archive[i] = (uint16_t)MAX_ARCHIVE_PERIOD;
    }
#endif    
}


