#include <log_to_mem.h>
#include <message_modbus.h>
#include <modbus_hmi.h>
#include <modbus_hmi_update.h>
#include <vector.h>

#include "control_station.h"
#include "global_time.h"
#include "modbus_table_v2.h"
#include "RS_modbus_pult.h"
#include "DSP281x_Device.h"
#include "MemoryFunctions.h"
#include "RS_modbus_svu.h"


#pragma DATA_SECTION(modbus_table_discret_in,".logs");
MODBUS_REG_STRUCT modbus_table_discret_in[SIZE_MODBUS_TABLE_DISCRET_REMOUTE];   //registers 10001-19999 modbus RTU

#pragma DATA_SECTION(modbus_table_discret_out,".logs");
MODBUS_REG_STRUCT modbus_table_discret_out[SIZE_MODBUS_TABLE_DISCRET_REMOUTE];  //registers 1-9999 modbus RTU

#pragma DATA_SECTION(modbus_table_analog_in, ".logs");
MODBUS_REG_STRUCT modbus_table_analog_in[SIZE_MODBUS_ANALOG_REMOUTE];   //registers 30001-39999 modbus RTU

#pragma DATA_SECTION(modbus_table_analog_out, ".logs");
//MODBUS_REG_STRUCT modbus_table_analog_out[700];  //registers 40001-49999 modbus RTU
MODBUS_REG_STRUCT modbus_table_analog_out[SIZE_MODBUS_ANALOG_REMOUTE];  //registers 40001-49999 modbus RTU



//unsigned int flag_waiting_answer = 1;
//unsigned int flag_message_sent = 0;

#pragma DATA_SECTION(log_to_HMI, ".logs");
Logs_with_modbus log_to_HMI = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

static int writeLogsArray();
static void prepareWriteLogsArray(void);
static void fillAnalogDataArrayForLogSend(int num_of_log);
///////////////////////////////////////////////////
///
///////////////////////////////////////////////////
void clear_table_remoute(void)
{
   int i;

   for (i=0;i<SIZE_MODBUS_TABLE_DISCRET_REMOUTE;i++)
   {
       modbus_table_discret_in[i].all = 0;
       modbus_table_discret_out[i].all = 0;
   }

   for (i=0;i<SIZE_MODBUS_ANALOG_REMOUTE;i++)
   {
       modbus_table_analog_in[i].all = 0;
       modbus_table_analog_out[i].all = 0;
   }




}
///////////////////////////////////////////////////
///
///////////////////////////////////////////////////

void fillLogArea() {
	unsigned int value = 0;
	unsigned int *p_memory = (unsigned int*)LOG_START_ADRES;
	long log_size = LOG_BUFFER_SIZE;
	while (log_size-- > 0) {
		*(p_memory++) = value;
		value += 1;
//		if (log_size % 8 == 0) {
//			value += 1;
//		}
	}
}
///////////////////////////////////////////////////
///
///////////////////////////////////////////////////

void setRegisterDiscreteOutput(int value, int adres) 
{
  int word_number = 0;
  int bit_number = 0;

    if (adres >= 0 && adres < SIZE_MODBUS_TABLE_DISCRET_BITS)
    {
//        word_number = (adres % 16 == 0) && (adres != 0) ? adres / 16 + 1 :
//                                                          adres / 16;
        word_number = (adres % 16 == 0) && (adres != 0) ? adres / 16 :
                                                          adres / 16;
        bit_number = adres % 16;
        
        if (word_number<SIZE_MODBUS_TABLE_DISCRET_REMOUTE)
        {
         if (value)
            modbus_table_discret_out[word_number].all |= 1 << bit_number;
		 else
		    modbus_table_discret_out[word_number].all &= ~(1 << bit_number);
        }
    }
}

///////////////////////////////////////////////////
///
///////////////////////////////////////////////////
int getRegisterDiscreteOutput(int adres) {
    int word_number = 0;
    int bit_number = 0;

    if (adres >= 0 && adres < SIZE_MODBUS_TABLE_DISCRET_BITS) {
        word_number = adres / 16;
        bit_number = adres % 16;
        return (modbus_table_discret_out[word_number].all >> bit_number) & 1;
    }

	return 0;
}

///////////////////////////////////////////////////
///
///////////////////////////////////////////////////
int readDiscreteOutputsFromRemote()
{
    int succed = 0;
    static unsigned int time_tick_modbus = 0;
    static unsigned int old_PWM_ticks = 0;
    static unsigned int count_write_to_modbus = 0;
    static int cur_position_buf_modbus1 = 0;

   ModbusRTUsetDiscretDataArray(modbus_table_discret_out, modbus_table_discret_out);

//    if (global_time.pwm_tics != old_PWM_ticks)
//    {
//        if (global_time.pwm_tics > old_PWM_ticks)
//            time_tick_modbus = time_tick_modbus + (global_time.pwm_tics - old_PWM_ticks);
//        else
//            time_tick_modbus++;
//    }
//    old_PWM_ticks = global_time.pwm_tics;
//    if (TIME_PAUSE_MODBUS < time_tick_modbus)
//    {
        if (!rs_b.flag_LEADING)
        {
//            time_tick_modbus = 0;

            if (control_station.flag_waiting_answer[CONTROL_STATION_INGETEAM_PULT_RS485] == 0)
                cur_position_buf_modbus1 = cur_position_buf_modbus1 + SIZE_BUF_WRITE_TO_MODBUS1_REMOUTE;

            if (cur_position_buf_modbus1 >= SIZE_MODBUS_TABLE_DISCRET_REMOUTE)
                cur_position_buf_modbus1 = 0;

            if ((cur_position_buf_modbus1 + SIZE_BUF_WRITE_TO_MODBUS1_REMOUTE) > SIZE_MODBUS_TABLE_DISCRET_REMOUTE)
                count_write_to_modbus = SIZE_MODBUS_TABLE_DISCRET_REMOUTE - cur_position_buf_modbus1;
            else
                count_write_to_modbus = SIZE_BUF_WRITE_TO_MODBUS1_REMOUTE;

            ModbusRTUsend1(&rs_b, 2,
                           ADR_MODBUS_TABLE_REMOUTE + cur_position_buf_modbus1,
                           count_write_to_modbus);
			succed = 1;
 //           control_station.flag_message_sent[CONTROL_STATION_INGETEAM_PULT_RS485] = 1;
        }
//    }
    return succed;
}

///////////////////////////////////////////////////
///
///////////////////////////////////////////////////
int writeSigleDiscreteDataToRemote(unsigned int adres)
{
	ModbusRTUsetDiscretDataArray(modbus_table_discret_out, modbus_table_discret_out);
	if (!rs_b.flag_LEADING && !control_station.flag_waiting_answer[CONTROL_STATION_INGETEAM_PULT_RS485] &&
	        (adres < SIZE_MODBUS_TABLE_DISCRET_BITS)) {
        ModbusRTUsend5(&rs_b, 2, ADR_MODBUS_TABLE_REMOUTE + adres);
		return 1;
    }
	return 0;
}

///////////////////////////////////////////////////
///
///////////////////////////////////////////////////
int writeSingleAnalogOutputToRemote(unsigned int adres)
{
	ModbusRTUsetDataArrays(modbus_table_analog_in, modbus_table_analog_out);
	if (!rs_b.flag_LEADING && !control_station.flag_waiting_answer[CONTROL_STATION_INGETEAM_PULT_RS485] &&
	        (adres < SIZE_MODBUS_ANALOG_REMOUTE)) {
        ModbusRTUsend6(&rs_b, 2, ADR_MODBUS_TABLE_REMOUTE + adres);
		return 1;
    }
	return 0;
}

///////////////////////////////////////////////////
///
///////////////////////////////////////////////////
int writeDiscreteDataToRemote()
{
    int succed = 0;
    static unsigned int old_time = 0;

    static unsigned int count_write_to_modbus = 0;
    static int cur_position_buf_modbus15 = 0;

    //ModbusRTUsetDiscretDataArray(modbus_table_discret_out, modbus_table_discret_out);
    ModbusRTUsetDiscretDataArray(modbus_table_discret_in, modbus_table_discret_out);


    if (!rs_b.flag_LEADING)
    {

//        if (rs_b.RS_DataReadyAnswerAnalyze)
//        {
//            cur_position_buf_modbus15 += SIZE_BUF_WRITE_TO_MODBUS15_REMOUTE;
//        }

        if (cur_position_buf_modbus15 >= (SIZE_MODBUS_TABLE_DISCRET_REMOUTE))
            cur_position_buf_modbus15 = 0;

        if ((cur_position_buf_modbus15 + SIZE_BUF_WRITE_TO_MODBUS15_REMOUTE) > (SIZE_MODBUS_TABLE_DISCRET_REMOUTE))
            count_write_to_modbus = SIZE_MODBUS_TABLE_DISCRET_REMOUTE - cur_position_buf_modbus15;
        else
            count_write_to_modbus = SIZE_BUF_WRITE_TO_MODBUS15_REMOUTE;

        //          count_write_to_modbus = SIZE_BUF_WRITE_TO_MODBUS16;
        //		  cur_position_buf_modbus=0;

        ModbusRTUsend15(&rs_b, 2, ADR_MODBUS_TABLE_REMOUTE + cur_position_buf_modbus15*16,
                        count_write_to_modbus*16);
//        ModbusRTUsend15(&rs_a, 2, ADR_MODBUS_TABLE_REMOUTE + cur_position_buf_modbus15*16,
//                        count_write_to_modbus*16);

        cur_position_buf_modbus15 += SIZE_BUF_WRITE_TO_MODBUS15_REMOUTE;

 //       control_station.flag_message_sent[CONTROL_STATION_INGETEAM_PULT_RS485] = 1;
 //       control_station.count_error_modbus_15[CONTROL_STATION_INGETEAM_PULT_RS485]++;

   //     hmi_watch_dog = !hmi_watch_dog; //was transmitted, need to change
        succed = 1;

    }
    return succed;
}

///////////////////////////////////////////////////
///
///////////////////////////////////////////////////
#define ADRESS_END_FIRST_BLOCK  20
#define ADRESS_START_PROTECTION_LEVELS 91

int readAnalogDataFromRemote()
{
    int succed = 0;
    static unsigned int old_time = 0;

    static unsigned int count_write_to_modbus = 0;
    static int cur_position_buf_modbus3 = 0, size_buf = SIZE_BUF_READ_FROM_MODBUS16_REMOUTE;


    ModbusRTUsetDataArrays(modbus_table_analog_in, modbus_table_analog_out);



    if (!rs_b.flag_LEADING)
    {

        if (control_station.flag_waiting_answer[CONTROL_STATION_INGETEAM_PULT_RS485] == 0)
            cur_position_buf_modbus3 = cur_position_buf_modbus3 + size_buf;

        if (cur_position_buf_modbus3 >= SIZE_ANALOG_DATA_FROM_MODBUS16_REMOUTE)
            cur_position_buf_modbus3 = 0;
        //����� � ������. ����������.
        if ((cur_position_buf_modbus3 > ADRESS_END_FIRST_BLOCK) &&
                (cur_position_buf_modbus3 < ADRESS_START_PROTECTION_LEVELS)) {
            cur_position_buf_modbus3 = ADRESS_START_PROTECTION_LEVELS;
        }
        if((cur_position_buf_modbus3 < ADRESS_END_FIRST_BLOCK) &&
                (cur_position_buf_modbus3 + size_buf) > ADRESS_END_FIRST_BLOCK) {
            count_write_to_modbus = ADRESS_END_FIRST_BLOCK - cur_position_buf_modbus3;
        }

        if ((cur_position_buf_modbus3 + size_buf) > SIZE_ANALOG_DATA_FROM_MODBUS16_REMOUTE)
            count_write_to_modbus = SIZE_ANALOG_DATA_FROM_MODBUS16_REMOUTE - cur_position_buf_modbus3;
        else
            count_write_to_modbus = size_buf;

        //          count_write_to_modbus = SIZE_BUF_WRITE_TO_MODBUS16;
        //		  cur_position_buf_modbus=0;


        //		  SendCommandModbus3(&rs_b,1,ADR_MODBUS_TABLE+cur_position_buf_modbus3,count_write_to_modbus);
        ModbusRTUsend4(&rs_b, 2,
                       ADR_MODBUS_TABLE_REMOUTE + cur_position_buf_modbus3,
                       count_write_to_modbus);
 //       control_station.count_error_modbus_4[CONTROL_STATION_INGETEAM_PULT_RS485]++;

 //       control_station.flag_message_sent[CONTROL_STATION_INGETEAM_PULT_RS485] = 1;
        succed = 1;
    }
    return succed;
}

///////////////////////////////////////////////////
///
///////////////////////////////////////////////////
int writeAnalogDataToRemote()
{
    int succed = 0;
    static unsigned int old_time = 0;

    static int count_write_to_modbus = 0;
    static int cur_position_buf_modbus16 = 0;


    ModbusRTUsetDataArrays(modbus_table_analog_in, modbus_table_analog_out);


    if (!rs_b.flag_LEADING)
    {
        if (control_station.flag_waiting_answer[CONTROL_STATION_INGETEAM_PULT_RS485] == 0)
            cur_position_buf_modbus16 = cur_position_buf_modbus16 + SIZE_BUF_WRITE_TO_MODBUS16_REMOUTE;

        if (cur_position_buf_modbus16 >= SIZE_ANALOG_DATA_REMOUTE)
            cur_position_buf_modbus16 = 0;

//        //����� � ������. ����������.
//        if ((cur_position_buf_modbus16 > ADRESS_END_FIRST_BLOCK) &&
//                (cur_position_buf_modbus16 < ADRESS_START_PROTECTION_LEVELS)) {
//            cur_position_buf_modbus16 = ADRESS_START_PROTECTION_LEVELS;
//        }

        if ((cur_position_buf_modbus16 + SIZE_BUF_WRITE_TO_MODBUS16_REMOUTE) > SIZE_ANALOG_DATA_REMOUTE)
            count_write_to_modbus = SIZE_ANALOG_DATA_REMOUTE - cur_position_buf_modbus16;
        else
            count_write_to_modbus = SIZE_BUF_WRITE_TO_MODBUS16_REMOUTE;

        ModbusRTUsend16(&rs_b, 2,
                        ADR_MODBUS_TABLE_REMOUTE + cur_position_buf_modbus16,
                        count_write_to_modbus);
 //       control_station.count_error_modbus_16[CONTROL_STATION_INGETEAM_PULT_RS485]++;

  //      control_station.flag_message_sent[CONTROL_STATION_INGETEAM_PULT_RS485] = 1;
        succed = 1;
    }
    return succed;
}

///////////////////////////////////////////////////
///
///////////////////////////////////////////////////
int sendLogToHMI()
{
	int succed = 0;
    unsigned int time_finish_transmitt = 0;
    if (log_to_HMI.send_log == 0)
    {
		log_to_HMI.step = 0;
		log_to_HMI.flag_data_received = 0;
		log_to_HMI.flag_log_array_sent = 0;
		log_to_HMI.log_size_sent = 0;
		log_to_HMI.current_address = 0;
		log_to_HMI.number_of_log = 0;
		setRegisterDiscreteOutput(0, 522);
	//	control_station.flag_message_sent[CONTROL_STATION_INGETEAM_PULT_RS485] = 1;
		return 1;
	}

	if (log_to_HMI.step == 0)
    {
        modbus_table_analog_out[3].all = logpar.count_log_params_fast_log;

        if (log_to_HMI.log_size_sent == 0 &&
            (writeSingleAnalogOutputToRemote(3) == 1))
        {
            log_to_HMI.log_size_sent = 1;
            succed = 1;
        } else if (log_to_HMI.log_size_sent == 1) {
            log_to_HMI.step = 1;
            log_to_HMI.flag_log_array_sent = 0;
            prepareWriteLogsArray();
            fillAnalogDataArrayForLogSend(log_to_HMI.number_of_log);
        }
    }
	if (log_to_HMI.step == 1) {
	    if (log_to_HMI.flag_log_array_sent == 0) {
	        succed = writeLogsArray(log_to_HMI.number_of_log);
	    } else {
	        log_to_HMI.step = 2;
	        init_timer_milisec(&time_finish_transmitt);
	    }
    }
	if (log_to_HMI.step == 2)
    {
        if (detect_pause_milisec(1000, &time_finish_transmitt)) {
            setRegisterDiscreteOutput(1, 522);
            if (writeDiscreteDataToRemote() == 1) {
                log_to_HMI.step = 3;
                succed = 1;
            }
        } else {
            succed = 1;
        }

    }
	if (log_to_HMI.step == 3) {
	    succed = readAnalogDataFromRemote();
	    if (modbus_table_analog_in[8].all == 1) {
	        if (detect_pause_milisec(1000, &time_finish_transmitt)) {
	            log_to_HMI.step = 4;
	        }
	    } else {
	        init_timer_milisec(&time_finish_transmitt);
	    }
	}
	if (log_to_HMI.step == 4) {
	    setRegisterDiscreteOutput(0, 522);
        if (writeDiscreteDataToRemote() == 1) {
            log_to_HMI.step = 5;
            succed = 1;
        }
	}
	if (log_to_HMI.step == 5) {
	    succed = readAnalogDataFromRemote();
	    if (modbus_table_analog_in[8].all == 0) {
            if (detect_pause_milisec(1000, &time_finish_transmitt) && log_to_HMI.number_of_log < (logpar.count_log_params_fast_log - 1)) {
                log_to_HMI.number_of_log += 1;
                fillAnalogDataArrayForLogSend(log_to_HMI.number_of_log);
                log_to_HMI.flag_log_array_sent = 0;
                log_to_HMI.step = 1;
            } else {
                succed = 1;
            }
        }
	}

	log_to_HMI.send_log = modbus_table_analog_in[7].all;
//	control_station.flag_message_sent[CONTROL_STATION_INGETEAM_PULT_RS485] = 1;
	return succed;
}

///////////////////////////////////////////////////
///
///////////////////////////////////////////////////

#define START_ARRAY_LOG_SEND    200
#define END_ARRAY_LOG_SEND      699
#define SIZE_ARRAY_LOG_SEND     (END_ARRAY_LOG_SEND - START_ARRAY_LOG_SEND + 1)

int writeLogsArray()
{
    unsigned long i = 0;
    int succed = 0;
	int *p_log_data = (int*)LOG_START_ADRES;
    ModbusRTUsetDataArrays(modbus_table_analog_in, modbus_table_analog_out);
    if (!rs_b.flag_LEADING)
    {
        ModbusRTUsend16(&rs_b, 2,
                        log_to_HMI.current_address,
                                log_to_HMI.count_write_to_modbus + 1);
        
        if (err_send_log_16 == 0) { //prev message without errors
            log_to_HMI.current_address = log_to_HMI.current_address + SIZE_BUF_WRITE_LOG_TO_MODBUS16;
        }
        if (log_to_HMI.current_address > END_ARRAY_LOG_SEND) {
            log_to_HMI.current_address = START_ARRAY_LOG_SEND;
//            log_to_HMI.flag_end_of_log = 1;
            log_to_HMI.flag_log_array_sent = 1;
        }
        if ((log_to_HMI.current_address + SIZE_BUF_WRITE_LOG_TO_MODBUS16) > END_ARRAY_LOG_SEND) {
            log_to_HMI.count_write_to_modbus = END_ARRAY_LOG_SEND - log_to_HMI.current_address;
        } else {
            log_to_HMI.count_write_to_modbus = SIZE_BUF_WRITE_LOG_TO_MODBUS16;
		}

		err_send_log_16 += 1;
		succed = 1;
	//	control_station.flag_message_sent[CONTROL_STATION_INGETEAM_PULT_RS485] = 1;
    }
    return succed;
}

void prepareWriteLogsArray(void) {
    log_to_HMI.start_log_address = logpar.addres_mem - logpar.count_log_params_fast_log * SIZE_ARRAY_LOG_SEND;
    if (log_to_HMI.start_log_address < START_ADDRESS_LOG) {
        log_to_HMI.start_log_address = END_ADDRESS_LOG - (START_ADDRESS_LOG - log_to_HMI.start_log_address);
    }
    log_to_HMI.log_address_step = logpar.count_log_params_fast_log;
}

void fillAnalogDataArrayForLogSend(int num_of_log) {
    int i = START_ARRAY_LOG_SEND;
    unsigned long current_address = log_to_HMI.start_log_address + num_of_log;
    for (i = START_ARRAY_LOG_SEND; i <= END_ARRAY_LOG_SEND; ++i) {
        modbus_table_analog_out[i].all = ReadMemory(current_address);
        current_address += log_to_HMI.log_address_step;
    }
    log_to_HMI.current_address = START_ARRAY_LOG_SEND;
    log_to_HMI.count_write_to_modbus = SIZE_BUF_WRITE_LOG_TO_MODBUS16;
}





///////////////////////////////////////////////////
///
///////////////////////////////////////////////////