//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#ifdef F_CPU
#undef F_CPU
#endif
#define F_CPU 16000000UL
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include <Arduino.h>
#include "IdiBusSerialLine.h"
#include "IDIBUS_4DC.h"
#include "IDIBUS_4ADC.h"
#include "IDIBUS_4CNT.h"
#include "IDIBUS_1Wire.h"
#include "IDIBUS_3Thermo1HT.h"
#include "IDIBUS_Speedster.h"
#include "IDIBUS_1xGen.h"
#include "MBOARD_POWER.h"
#include <avr/wdt.h>

//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//IDIBUS MASTER V0.26 beta
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IdiBusSerialLine Serial_Line0;
IdiBusSerialLine Serial_Line1;
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void setup()
{
 MBOARD_POWER_OFF_ON();
 delay(50);		//	Power on delay for external periphery
 
 //Arduino Variant
 IDIBUS_SERIAL_INIT_TYPEDEF L0Init;
 L0Init.USART_NUMBER  = IDIBUS_SERIAL_USART2;	//	select USART
 L0Init.TIMER_NUMBER  = IDIBUS_TIMER_1;			//	select timer 
 L0Init.CONFIG        = IDIBUS_SERIAL_8N2;		//	8 bit, 2 stop
 L0Init.RS485_DIR_PIN         = 6;				//	direction pin in-out
 L0Init.BAUDRATE_DIPSW_S0_PIN = 9;				//	speed selector pins
 L0Init.BAUDRATE_DIPSW_S1_PIN = 8;
 L0Init.BAUDRATE_DIPSW_S2_PIN = 7;
 Serial_Line0.Init(&L0Init);					//	Init line with with config above	
 Serial_Line0.UpdateBaudrateFromDipSwitch();	//	speed setup
 Serial_Line0.Start();							//	run!
 
 // Standard pinout variant
 IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF L1Init;
 L1Init.USART_NUMBER  = IDIBUS_SERIAL_USART1;
 L1Init.TIMER_NUMBER  = IDIBUS_TIMER_3;
 L1Init.CONFIG        = IDIBUS_SERIAL_8N2;
 L1Init.RS485_DIR_GPIO.PORT       = &PORTL;
 L1Init.RS485_DIR_GPIO.PIN_NUM    = 6;
 L1Init.BAUDRATE_DIPSW.S0.PORT    = &PORTD;
 L1Init.BAUDRATE_DIPSW.S0.PIN_NUM = 1;
 L1Init.BAUDRATE_DIPSW.S1.PORT    = &PORTD;
 L1Init.BAUDRATE_DIPSW.S1.PIN_NUM = 0;
 L1Init.BAUDRATE_DIPSW.S2.PORT    = &PORTL;
 L1Init.BAUDRATE_DIPSW.S2.PIN_NUM = 7;
 Serial_Line1.Init(&L1Init);
 Serial_Line1.UpdateBaudrateFromDipSwitch();
 Serial_Line1.Start();
 
 //Serial.begin(115200,SERIAL_8N2);	//	usart0 for debug
 
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 //	Enable power out 24V on main board (to slaves)
 //#define BAUD 16000000UL/16/250000UL-1		// BAUD speed = 250000 bod	
 //UBRR3 = (uint16_t)(BAUD);			//	USART BAUD RATE INIT
 //UCSR3B = (1<<RXEN3)|(1<<TXEN3);	//	USART ENABLE TX RX
 //while (!(UCSR3A & (1<<UDRE3)));	//	wait for send
 //UDR3 = 'R';						//	send 'R'
 //while (!(UCSR3A & (1<<UDRE3)));	//	wait for send
 //UDR3 = '+';						//  send '+'
 //delay(500);						//	Power on delay for external periphery
 
 volatile uint8_t ErrorCode;		//	buffer for error codes
 IdiBusLongOpData LopData;			//	Long operation data (not used in current example)
 Inputs Settings;
 
 IdiBus_1xGen TEMP(&Serial_Line0, 2);
 ErrorCode = TEMP.c_Init();
 delay(1000);
 
 Settings.first_mode_time = 1;
 Settings.first_mode_pwm_value = 40000;
 Settings.first_mode_f = 40;
 Settings.first_mode_invert = 1;  // 0 || 1
 //Settings.first_mode_R1 = 0;  // 0 || 1
 
 Settings.second_mode_time = 1;
 Settings.second_mode_pwm_value = 20000;
 Settings.second_mode_f = 60;
 Settings.second_mode_invert = 1;  // 0 || 1
 //Settings.second_mode_R1 = 1;   // 0 || 1
 
 uint8_t TxData[10] = {Settings.first_mode_time,
	 (uint8_t)((Settings.first_mode_pwm_value >> 8) & 0xFF), (uint8_t)(Settings.first_mode_pwm_value & 0xFF),
	 Settings.first_mode_f, Settings.first_mode_invert,
	 Settings.second_mode_time,
	 (uint8_t)((Settings.second_mode_pwm_value >> 8) & 0xFF), (uint8_t)(Settings.second_mode_pwm_value & 0xFF),
 Settings.second_mode_f, Settings.second_mode_invert};

 TEMP.start_SPI(TxData);
 //TEMP.reset_STM();
 
 Serial_Line1.UpdateBaudrateFromDipSwitch();
 Serial_Line0.UpdateBaudrateFromDipSwitch();
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
struct Statistic{
	uint32_t Ok;
	uint32_t Lost;
	uint32_t Broken;
	uint32_t Total;
};

Statistic stats[6];
uint8_t PacketCounter;
IdiBus_Test IDITEST[6];
*/
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void loop()
{

/*
	PacketCounter = 0;
	const uint8_t baseAddr = 80;
	const uint8_t num = 4;
	for (uint8_t addr = 0; addr < num; addr++){
		if ((addr&1) == 0)
		IDITEST[addr] = IdiBus_Test(&Serial_Line0,baseAddr+(addr>>1));
		else
		IDITEST[addr] = IdiBus_Test(&Serial_Line1,baseAddr+(addr>>1));
		stats[addr].Ok = 0;
		stats[addr].Lost = 0;
		stats[addr].Broken = 0;
		stats[addr].Total = 0;
	}

	for (uint8_t addr = 0; addr < num;) {
		ErrorCode = IDITEST[addr].c_Init();
		delay(1000);
		if (ErrorCode != IDIER_NOPE) {
			Serial.print("[ERROR] Unable to init module ");
			Serial.print(1<<((addr>>1)+5));
			Serial.print(" | Line ");
			Serial.print(addr&1);
			Serial.print(". Check the connection! \n");
			delay(1000);
		} else
		addr++;
	}
	Serial.write("[INFO] Modules inited successfully\n");

	while(1) {
		for (uint8_t id = 0; id < num; id++){
			ErrorCode = IDITEST[id].sendPacket(0);

			Statistic *stat = &stats[id];
			stat->Total++;

			if (ErrorCode == IDIERMST_RCV_TIMEOUT) {
				stat->Lost++;
				} else if (ErrorCode != IDIER_NOPE) {
				stat->Broken++;
				} else {
				IDIBUS_Test_DATA_TYPE data = IDITEST[id].getChData(0);
				
				uint8_t fail = 0;

				for (uint16_t i = 0; i < 256; i++){
					if (data.DATA[i] != data.RNG[i]) {
						fail = 1;
						break;
					}
				}

				if (fail == 1)
				stat->Broken++;
				else
				stat->Ok++;
			}
		}

		PacketCounter++;
		if (PacketCounter == 8) {
			for (uint8_t id = 0; id < num; id++){
				Serial.print("[INFO] Module #");
				Serial.print(baseAddr+(id>>1));
				Serial.print(" Line:");
				Serial.print(id&1);
				Serial.print(" | ");
				Serial.print(stats[id].Ok);
				Serial.print(" | ");
				Serial.print(stats[id].Lost);
				Serial.print(" | ");
				Serial.print(stats[id].Broken);
				Serial.print(" | ");
				Serial.println(stats[id].Total);
			}
			PacketCounter = 0;
			Serial_Line0.UpdateBaudrateFromDipSwitch();
			Serial_Line1.UpdateBaudrateFromDipSwitch();
		}
	}
	*/
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 /*
 Egor code for loop function
  
 IdiBus_4DC IDB4DC(&Serial_Line1, 122);

 ErrorCode = IDB4DC.c_Init();
 delay(1000);
 ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 0, 10);
 ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 2, 10);
 
 uint8_t TxData;
 IdiBusMMESG Group1(IDIBUS_GROUP_10_ADDR, &TxData, 1);
 Group1.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE;
 
 while (1)
	{
	 Serial.write((uint8_t*)"echo", sizeof("echo")-1);
	 
	 TxData = 0;
	 Serial_Line1.sendMMESG(&Group1);
	 delay(2000);
	 TxData = 1;
	 Serial_Line1.sendMMESG(&Group1);
	 delay(2000);
	}*/
 
/* 
 ErrorCode[0] = IDB4DC.c_Init();
 delay(1000);
 ErrorCode[1] = IDB4DC.c_WriteSnIPv4IPv6(0xAABBCCDD, 0xA1A2A3A4, 0xA5A6A7A8, 0xB1B2B3B4, 0xB5B6B7B8);
 do { ErrorCode[2] = IDB4DC.c_CheckModuleLongOp(); }
 while ( (LopData = IDB4DC.getModuleLongOpData()).State == IDILONGOP_STATE_IN_PROC );
 
 ErrorCode[3] = IDB4DC.INPV_DEV.getInputVoltage();
 INPV_Data = IDB4DC.INPV_DEV.getChData();
 
 IDB4DC.PSUC_DEV.setAllChVoltage(5000, 6000, 7000, 8000);
 IDB4DC.PSUC_DEV.setAllChState(1);
  while (1)
	{
	 IDB4DC.PSUC_DEV.setAllChState(0, 1, 0, 1);
	 delay(2000);
	 IDB4DC.PSUC_DEV.setAllChState(1, 0, 1, 0);
	 delay(2000);
	}
*/
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
uint8_t MBOARD_POWER_SET(uint8_t juction, uint8_t set)	//	power channel ON/OFF
{
	Serial3.begin(115200,SERIAL_8N1);	//	usart3 for 328pb on MBoard
	uint8_t string[2];
	if((juction==MBOARD_POWER_J89_05V)&&(set==MBOARD_POWER_ON))
	{
		Serial3.print("5+"); delay(10);
		Serial3.readBytes(string, 2);
		if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK;
	}
	else if((juction==MBOARD_POWER_J89_05V)&&(set==MBOARD_POWER_OFF))
	{
		Serial3.print("5-"); delay(10);
		Serial3.readBytes(string, 2);
		if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK;
	}
	else if((juction==MBOARD_POWER_J89_24V)&&(set==MBOARD_POWER_ON))
	{
		Serial3.print("J+"); delay(10);
		Serial3.readBytes(string, 2);
		if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK;
	}
	else if((juction==MBOARD_POWER_J89_24V)&&(set==MBOARD_POWER_OFF))
	{
		Serial3.print("J-"); delay(10);
		Serial3.readBytes(string, 2);
		if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK;
	}
	else if((juction==MBOARD_POWER_J67_24V)&&(set==MBOARD_POWER_ON))
	{
		Serial3.print("R+"); delay(10);
		Serial3.readBytes(string, 2);
		if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK;
	}
	else if((juction==MBOARD_POWER_J67_24V)&&(set==MBOARD_POWER_OFF))
	{
		Serial3.print("R-"); delay(10);
		Serial3.readBytes(string, 2);
		if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK;
	}
	while(Serial3.available()>0) string[0]=Serial3.read();
	return MBOARD_POWER_ERR;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void MBOARD_POWER_OFF_ON(void)	//	выключение, пауза и последовательное включение всех питаний
{
	MBOARD_POWER_SET(MBOARD_POWER_J89_05V, MBOARD_POWER_OFF);
	MBOARD_POWER_SET(MBOARD_POWER_J89_24V, MBOARD_POWER_OFF);
	MBOARD_POWER_SET(MBOARD_POWER_J67_24V, MBOARD_POWER_OFF);
	delay(1000);wdt_reset();
	MBOARD_POWER_SET(MBOARD_POWER_J89_05V, MBOARD_POWER_ON);
	delay(500);wdt_reset();
	MBOARD_POWER_SET(MBOARD_POWER_J89_24V, MBOARD_POWER_ON);
	delay(500);wdt_reset();
	MBOARD_POWER_SET(MBOARD_POWER_J67_24V, MBOARD_POWER_ON);
	delay(1000);wdt_reset();
	return;
}