/**************INCLUDE BLOCK**************/

#include "modbus.h"
#include "main.h"
#include "usart.h"
#include "OCPP.h"
#include "w25qxx.h"

/***********INCLUDE BLOCK END*************/


/***** Data Type, Constant, and Macro Definitions *****/

#define M1_IV 0
#define M2_IV 1
#define M1_KW 2
#define M2_KW 3
#define M1_KWH 4
#define M2_KWH 5

union
{
	unsigned short int word;
	uint32_t dword;
	float dfloat;
	unsigned char byte[4];
}split_int;


/* Global variables*/

uint16_t enrgyread1_timouttick=5000,enrgyread2_timouttick=5000,enrgyread3_timouttick=5000;
uint8_t energymeter_err[3];
volatile OCPP_States OCPP_State_ACType2;
 char wifi_connected;
 unsigned char meterquerycntr=0;

unsigned char modbus_cmd;
unsigned short int modbus_addr;
short int modbus_dat;
unsigned short int modbus_length;
unsigned short int modbus_crc16;
unsigned short int cal_crc;
uint8_t rxmsg[100];//,hmi[25];
volatile uint32_t energy, energy2, energy3, ocpp_energy;
uint16_t temp;

/* Extern Data Declarations */

extern uint8_t powerfailure_flag;
extern uint8_t meter_failed;
extern uint8_t gun_3,gun_2,gun_1,gun,RCD2_stop,RCD1_stop,RCD3_stop;
extern char Send_meter;

/* Static Data Declarations */

static unsigned char modbus_device_addr;

/***** Data Type, Constant, and Macro Definitions END *****/


/***** Public Function Bodies *****/
uint16_t ModCRC(uint8_t buf[], int len);

/***** Public Function Bodies END *****/


//#include "settings.h"

/**
 * @brief Calculate the CRC16 checksum for a given data block.
 *
 * This function calculates the CRC16 checksum using the CCITT standard polynomial.
 *
 * @param[in] nData Pointer to the data block.
 * @param[in] wLength Length of the data block.
 * @return The calculated CRC16 checksum.
 */
unsigned short int CRC16 (unsigned char *nData, unsigned short int wLength)
{
static const unsigned short int wCRCTable[] = {
0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,
0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,
0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,
0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,
0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,
0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,
0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,
0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,
0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,
0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,
0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,
0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,
0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,
0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,
0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,
0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,
0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,
0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,
0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,
0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,
0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,
0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,
0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,
0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,
0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,
0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,
0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,
0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,
0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,
0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040 };

unsigned char nTemp;
unsigned short int wCRCWord = 0xFFFF;

   while (wLength--)
   {
      nTemp = *nData++ ^ wCRCWord;
      wCRCWord >>= 8;
      wCRCWord ^= wCRCTable[nTemp];
   }
   return wCRCWord;
}
/**
 * @brief Calculate the Modbus CRC (Cyclic Redundancy Check) for a given data block.
 *
 * This function calculates the Modbus CRC using the standard polynomial 0xA001.
 *
 * @param[in] buf Pointer to the data block.
 * @param[in] len Length of the data block.
 * @return The calculated Modbus CRC.
 */
uint16_t ModCRC(uint8_t buf[], int len)
{
	uint16_t crc = 0xFFFF;

  for (int pos = 0; pos < len; pos++) {
    crc ^= (uint16_t)buf[pos];          // XOR byte into least sig. byte of crc

    for (int i = 8; i != 0; i--) {    // Loop over each bit
      if ((crc & 0x0001) != 0) {      // If the LSB is set
        crc >>= 1;                    // Shift right and XOR 0xA001
        crc ^= 0xA001;
      }
      else                            // Else LSB is not set
        crc >>= 1;                    // Just shift right
    }
  }
  // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)
  return crc;
}
/**
 * @brief Check and process Modbus messages.
 *
 * This function checks and processes Modbus messages received via UART.
 * It calculates the CRC, checks the validity of the message, and updates charger status accordingly.
 *
 * @return NA (No meaningful return value).
 */
void modbus_check(void)
{
	char i=0;
	enrgyread1_timouttick=20000;
	modbus_device_addr=rxmsg[0];
	uint16_t lclCRCchk=0;
	unsigned short TEMP=0;
	uint8_t temparray[2];
#if defined(selecdual)
		if(modbus_device_addr==0x01 && meterquerycntr == 0)
	{
	split_int.byte[3] = /* charger_status_G1.hmi[6] */ rxmsg[3];
	split_int.byte[2] = /* charger_status_G1.hmi[7] */ rxmsg[4];
	split_int.byte[1] = /* cha-rger_status_G1.hmi[8] */ rxmsg[5];
	split_int.byte[0] = /* charger_status_G1.hmi[9] */rxmsg[6]; //VOLTAGE
	charger_status_G1.voltage =  (uint16_t)split_int.dfloat;//;/10000;

	split_int.byte[3] = /* charger_status_G2.hmi[10] = */rxmsg[19];
	split_int.byte[2] = /* charger_status_G2.hmi[11] = */rxmsg[20];
	split_int.byte[1] = /* charger_status_G2.hmi[12] = */rxmsg[21];
	split_int.byte[0] = /* charger_status_G2.hmi[13] = */rxmsg[22]; //CURRENT
	charger_status_G1.current = split_int.dfloat;///10000;
	if(OCPP.under_voltage > charger_status_G1.voltage)
				{
					charger_status_G1.error = UnderVoltage;
				}
			else if(OCPP.over_voltage < charger_status_G1.voltage)
			{
				charger_status_G1.error = OverVoltage;
			}
			else if(OCPP.over_current_AC02 < charger_status_G1.current)
			{
				charger_status_G1.error = OverCurrentFailure;
			}
			else{
					if(charger_status_G1.error == UnderVoltage || charger_status_G1.error == OverVoltage )
					{
						charger_status_G1.error = NoError_ChargerPoint;
					}
			}
			///////////////////////////////////////////////////////////////////////////////////////



			if(charger_status_G1.error == UnderVoltage)
			{

			}
			else if(charger_status_G1.error == OverVoltage)
			{

			}
			else if(charger_status_G1.error == OverCurrentFailure)
			{

			}
			else if(charger_status_G1.error == GroundFailure)
			{

			}
			else if(charger_status_G1.error == InternalError)
			{

			}
			else
			{
				//////////////////////////////////////V3.3.1///////////////////////////////
				if(charger_status_G1.stop == Error || charger_status_G1.charging_status == Faulted_ChargerPoint )
				{
					charger_status_G1.stop = Stoped;
					enQueue(G1_StatusNotification);
					gun_1 = G_NoError;

					if(Ocpp_Setting.Operative[1] == Available_ChargerPoint)
					  {
						 charger_status_G1.charging_status = Available_ChargerPoint;
					  }
					  else if(Ocpp_Setting.Operative[1] == Unavailable_ChargerPoint)
					  {
						  charger_status_G1.charging_status = Unavailable_ChargerPoint;
					  }

				}
				charger_status_G1.error = NoError_ChargerPoint;
			}

			if((charger_status_G1.error == UnderVoltage) || (charger_status_G1.error == OverVoltage) || (charger_status_G1.error == OverCurrentFailure) || (charger_status_G1.error == InternalError) || (charger_status_G1.error == GroundFailure ))
			{
				if(charger_status_G1.start == Started)
				{
					charger_status_G1.stop = Try_To_Stop;
					gun_1 = G_Discharging;
				}
				else if(charger_status_G1.charging_status != Faulted_ChargerPoint)
				{
					gun_1 = G_Error;
					enQueue(G1_StatusNotification);
				}

				charger_status_G1.stop =Error;
				charger_status_G1.charging_status = Faulted_ChargerPoint;
				if(charger_status_G1.error != PowerSwitchFailure)			//V4.x.8
				{
				charger_status_G1.reson= Other;
				}
			}

			meterquerycntr =1;

			charger_status_G1.hmi[0] = 0x5a;
				charger_status_G1.hmi[1] = 0xa5;
				charger_status_G1.hmi[2] = 19;
				charger_status_G1.hmi[3] = 0x82;
				charger_status_G1.hmi[4] = 0x10;
				charger_status_G1.hmi[5] = 0x00;

				split_int.dword = (charger_status_G1.voltage*10000);

				charger_status_G1.hmi[6] = split_int.byte[3];
				charger_status_G1.hmi[7] = split_int.byte[2];
				charger_status_G1.hmi[8] = split_int.byte[1];
				charger_status_G1.hmi[9] = split_int.byte[0]; //Voltage

				split_int.dword = (charger_status_G1.current*10000);
				charger_status_G1.hmi[10] = split_int.byte[3];
				charger_status_G1.hmi[11] = split_int.byte[2];
				charger_status_G1.hmi[12] = split_int.byte[1];
				charger_status_G1.hmi[13] = split_int.byte[0]; //current





			}
		else if(modbus_device_addr==0x02 && meterquerycntr == 1)
		{
			split_int.byte[3] = /* charger_status_G1.hmi[6] */ rxmsg[3];
			split_int.byte[2] = /* charger_status_G1.hmi[7] */ rxmsg[4];
			split_int.byte[1] = /* cha-rger_status_G1.hmi[8] */ rxmsg[5];
			split_int.byte[0] = /* charger_status_G1.hmi[9] */rxmsg[6]; //VOLTAGE
			charger_status_G2.voltage =  (uint16_t)split_int.dfloat;//;/10000;

			split_int.byte[3] = /* charger_status_G2.hmi[10] = */rxmsg[19];
			split_int.byte[2] = /* charger_status_G2.hmi[11] = */rxmsg[20];
			split_int.byte[1] = /* charger_status_G2.hmi[12] = */rxmsg[21];
			split_int.byte[0] = /* charger_status_G2.hmi[13] = */rxmsg[22]; //CURRENT
			charger_status_G2.current = split_int.dfloat;///10000;




			if(OCPP.under_voltage > charger_status_G2.voltage && (powerfailure_flag!=5))
			{
				charger_status_G2.error = UnderVoltage;

			}
			else if(OCPP.over_voltage < charger_status_G2.voltage)
			{
				charger_status_G2.error = OverVoltage;

			}
			else if(OCPP.over_current_AC02 < charger_status_G2.current)
			{
				charger_status_G2.error = OverCurrentFailure;

			}
			else if(charger_status_G2.error == GroundFailure)
			{

			}
			else if(charger_status_G2.error == PowerSwitchFailure)
			{

			}
			else if(charger_status_G2.error == InternalError)
			{

			}
			else
			{
				//////////////////////////////////////V3.3.1///////////////////////////////
				if(charger_status_G2.stop == Error ||  charger_status_G2.charging_status == Faulted_ChargerPoint)
				{
					charger_status_G2.stop = Stoped;
					enQueue(G2_StatusNotification);
					gun_2 = G_NoError;
					 if(Ocpp_Setting.Operative[2] == Available_ChargerPoint)
					  {
						 charger_status_G2.charging_status = Available_ChargerPoint;
					  }
					  else if(Ocpp_Setting.Operative[2] == Unavailable_ChargerPoint)
					  {
						  charger_status_G2.charging_status = Unavailable_ChargerPoint;
					  }
					//charger_status_G2.charging_status = Available_ChargerPoint;
				}
				charger_status_G2.error = NoError_ChargerPoint;
			}

			if((charger_status_G2.error == UnderVoltage) || (charger_status_G2.error == OverVoltage) || (charger_status_G2.error == OverCurrentFailure) || (charger_status_G2.error == GroundFailure) || (charger_status_G2.error == PowerSwitchFailure) || (charger_status_G2.error == InternalError)||(charger_status_G2.error == OtherError) || charger_status_G2.error == InternalError)
			{
				if(charger_status_G2.start == Started)
				{
					charger_status_G2.stop = Try_To_Stop;
					gun_2 = G_Discharging;
				}
				else if(charger_status_G2.charging_status != Faulted_ChargerPoint)
				{
					gun_2 = G_Error;
					enQueue(G2_StatusNotification);
				}

				charger_status_G2.stop =Error;
				charger_status_G2.charging_status = Faulted_ChargerPoint;
				if(charger_status_G2.error != PowerSwitchFailure)			//V4.x.8
				{
				charger_status_G2.reson= Other;
				}
			}
			///////////////////////////////////////////////////////////////////////////////////////







			charger_status_G2.hmi[0] = 0x5a;
			charger_status_G2.hmi[1] = 0xa5;
			charger_status_G2.hmi[2] = 19;
			charger_status_G2.hmi[3] = 0x82;
			charger_status_G2.hmi[4] = 0x10;
			charger_status_G2.hmi[5] = 0x00;


			split_int.dword = (charger_status_G2.voltage*10000);

			charger_status_G2.hmi[6] = split_int.byte[3];
			charger_status_G2.hmi[7] = split_int.byte[2];
			charger_status_G2.hmi[8] = split_int.byte[1];
			charger_status_G2.hmi[9] = split_int.byte[0]; //Voltage

			split_int.dword = (charger_status_G2.current*10000);
			charger_status_G2.hmi[10] = split_int.byte[3];
			charger_status_G2.hmi[11] = split_int.byte[2];
			charger_status_G2.hmi[12] = split_int.byte[1];
			charger_status_G2.hmi[13] = split_int.byte[0]; //current




			meterquerycntr=2;

		}
		else if(modbus_device_addr==0x01 && meterquerycntr == 2)
		{
			split_int.byte[3] =  rxmsg[3];
			split_int.byte[2] =  rxmsg[4];
			split_int.byte[1] =  rxmsg[5];
			split_int.byte[0] = rxmsg[6]; //KW
			charger_status_G1.power = (float)(split_int.dfloat*1000);///10000;

			split_int.dword = (charger_status_G1.power*10000);
			charger_status_G1.hmi[14] = split_int.byte[3];
			charger_status_G1.hmi[15] = split_int.byte[2];
			charger_status_G1.hmi[16] = split_int.byte[1];
			charger_status_G1.hmi[17] = split_int.byte[0]; //power

			meterquerycntr =3;
		}
		else if(modbus_device_addr==0x02 && meterquerycntr == 3)
		{
			split_int.byte[3] =  rxmsg[3];
			split_int.byte[2] =  rxmsg[4];
			split_int.byte[1] =  rxmsg[5];
			split_int.byte[0] = rxmsg[6]; //KW
			charger_status_G2.power = (float)(split_int.dfloat*1000);///10000;


			split_int.dword = (charger_status_G2.power*10000);
			charger_status_G2.hmi[14] = split_int.byte[3];
			charger_status_G2.hmi[15] = split_int.byte[2];
			charger_status_G2.hmi[16] = split_int.byte[1];
			charger_status_G2.hmi[17] = split_int.byte[0]; //power





			meterquerycntr =4;
		}

		else if(modbus_device_addr==0x01 && meterquerycntr == 4)
		{
			split_int.byte[3] /*= hmi[18]*/ =rxmsg[3];
			split_int.byte[2] /*= hmi[19]*/ =rxmsg[4];
			split_int.byte[1] /*= hmi[20]*/ =rxmsg[5];
			split_int.byte[0] /*= hmi[21]*/ =rxmsg[6]; //ENERGY


			energy = (uint32_t)(split_int.dfloat*100);///10;


			if(charger_status_G1.charging_status == Charging_ChargerPoint)
			{
				charger_status_G1.energy =  (unsigned long int)energy - (unsigned int)charger_status_G1.start_energy;
			}
			else
			{
				charger_status_G1.energy = 0;
			}

			split_int.dword = charger_status_G1.energy;
			charger_status_G1.hmi[18] = split_int.byte[3];
			charger_status_G1.hmi[19] = split_int.byte[2];
			charger_status_G1.hmi[20] = split_int.byte[1];
			charger_status_G1.hmi[21] = split_int.byte[0]; //KWh

			meterquerycntr =5;
		}
		else if(modbus_device_addr==0x02 && meterquerycntr == 5)
		{
			split_int.byte[3] /*= hmi[18]*/ =rxmsg[3];
			split_int.byte[2] /*= hmi[19]*/ =rxmsg[4];
			split_int.byte[1] /*= hmi[20]*/ =rxmsg[5];
			split_int.byte[0] /*= hmi[21]*/ =rxmsg[6]; //ENERGY

			energy2 = (uint32_t)(split_int.dfloat*100);///10;


			if(charger_status_G2.charging_status == Charging_ChargerPoint)
			{
				charger_status_G2.energy =  (unsigned long int)energy2 - (unsigned int)charger_status_G2.start_energy;
			}
			else
			{
				charger_status_G2.energy = 0;
			}

			split_int.dword = charger_status_G2.energy;
			charger_status_G2.hmi[18] = split_int.byte[3];
			charger_status_G2.hmi[19] = split_int.byte[2];
			charger_status_G2.hmi[20] = split_int.byte[1];
			charger_status_G2.hmi[21] = split_int.byte[0]; //KWh

			meterquerycntr =0;
		}
#else
#if meter == normal

	//uint8_t buff[50];
		lclCRCchk=ModCRC(rxmsg,35);
		TEMP=(lclCRCchk & 0X00FF);
		temparray[0] = (uint8_t)(TEMP);
		lclCRCchk>>=8;
		TEMP=0;
		TEMP=(lclCRCchk & 0X00FF);
		temparray[1] = (uint8_t)(TEMP );
	if(modbus_device_addr==0x01)
	{
			if((temparray[0] == rxmsg[35] ) &&  (temparray[1] == rxmsg[36]))
			{
					charger_status_G1.hmi[0] = 0x5a;
					charger_status_G1.hmi[1] = 0xa5;
					charger_status_G1.hmi[2] = 19;
					charger_status_G1.hmi[3] = 0x82;
					charger_status_G1.hmi[4] = 0x10;
					charger_status_G1.hmi[5] = 0x00;

					split_int.byte[3] = charger_status_G1.hmi[6] =rxmsg[3];
					split_int.byte[2] = charger_status_G1.hmi[7] =rxmsg[4];
					split_int.byte[1] = charger_status_G1.hmi[8] =rxmsg[5];
					split_int.byte[0] = charger_status_G1.hmi[9] =rxmsg[6]; //VOLTAGE
					charger_status_G1.voltage = split_int.dword/10000;

					split_int.byte[3] = charger_status_G1.hmi[10] =rxmsg[7];
					split_int.byte[2] = charger_status_G1.hmi[11] =rxmsg[8];
					split_int.byte[1] = charger_status_G1.hmi[12] =rxmsg[9];
					split_int.byte[0] = charger_status_G1.hmi[13] =rxmsg[10]; //CURRENT
					charger_status_G1.current = (float)split_int.dword/10000;

					split_int.byte[3] = charger_status_G1.hmi[14] =rxmsg[11];
					split_int.byte[2] = charger_status_G1.hmi[15] =rxmsg[12];
					split_int.byte[1] = charger_status_G1.hmi[16] =rxmsg[13];
					split_int.byte[0] = charger_status_G1.hmi[17] =rxmsg[14]; //KW
					charger_status_G1.power = (float)split_int.dword/10000;

					split_int.byte[3] /*= hmi[18]*/ =rxmsg[15];
					split_int.byte[2] /*= hmi[19]*/ =rxmsg[16];
					split_int.byte[1] /*= hmi[20]*/ =rxmsg[17];
					split_int.byte[0] /*= hmi[21]*/ =rxmsg[18]; //ENERGY

					energy = (uint32_t)split_int.dword/10;

#ifdef OLD
					if(OCPP.under_voltage > charger_status_G1.voltage)
					{
						charger_status_G1.error = UnderVoltage;
					}
					else if(OCPP.over_voltage < charger_status_G1.voltage)
					{
						charger_status_G1.error = OverVoltage;
					}
					else if(OCPP.over_current_AC02 < charger_status_G1.current)
					{
						charger_status_G1.error = OverCurrentFailure;
					}
					else{
							if(charger_status_G1.error == UnderVoltage || charger_status_G1.error == OverVoltage )
							{
								charger_status_G1.error = NoError_ChargerPoint;
							}
					}
#endif
					///////////////////////////////////////////////////////////////////////////////////////

					if(charger_status_G1.charging_status == Charging_ChargerPoint)
					{
						charger_status_G1.energy =  (unsigned long int)energy - (unsigned int)charger_status_G1.start_energy;
					}
					else
					{
						charger_status_G1.energy = 0;
					}


				split_int.dword = charger_status_G1.energy;
				charger_status_G1.hmi[18] = split_int.byte[3];
				charger_status_G1.hmi[19] = split_int.byte[2];
				charger_status_G1.hmi[20] = split_int.byte[1];
				charger_status_G1.hmi[21] = split_int.byte[0]; //KWh
		}

	}
#else
	if(modbus_device_addr==0x01)
	{
		lclCRCchk=ModCRC(rxmsg,95);
		TEMP=(lclCRCchk & 0X00FF);
		temparray[0] = (uint8_t)(TEMP);
		lclCRCchk>>=8;
		TEMP=0;
		TEMP=(lclCRCchk & 0X00FF);
		temparray[1] = (uint8_t)(TEMP );

		if((temparray[0] == rxmsg[95] ) &&  (temparray[1] == rxmsg[96]))
		{
		meter_failed=0;

		split_int.byte[3] = /* charger_status_G1.hmi[6] */ rxmsg[3];
		split_int.byte[2] = /* charger_status_G1.hmi[7] */ rxmsg[4];
		split_int.byte[1] = /* cha-rger_status_G1.hmi[8] */ rxmsg[5];
		split_int.byte[0] = /* charger_status_G1.hmi[9] */rxmsg[6]; //VOLTAGE
		charger_status_G1.voltage =  (uint16_t)split_int.dfloat;//;/10000;

		split_int.byte[3] = /* charger_status_G2.hmi[10] = */rxmsg[19];
		split_int.byte[2] = /* charger_status_G2.hmi[11] = */rxmsg[20];
		split_int.byte[1] = /* charger_status_G2.hmi[12] = */rxmsg[21];
		split_int.byte[0] = /* charger_status_G2.hmi[13] = */rxmsg[22]; //CURRENT
		charger_status_G1.current = split_int.dfloat;///10000;
		//charger_status_G1.current=3.125;

		split_int.byte[3] = /* charger_status_G2.hmi[14] = */ rxmsg[59];
		split_int.byte[2] = /* charger_status_G2.hmi[15] = */ rxmsg[60];
		split_int.byte[1] = /* charger_status_G2.hmi[16] = */ rxmsg[61];
		split_int.byte[0] = /* charger_status_G2.hmi[17] = */rxmsg[62]; //KW
		charger_status_G1.power = (float)(split_int.dfloat*1000);///10000;

		split_int.byte[3] /*= hmi[18]*/ =rxmsg[91];
		split_int.byte[2] /*= hmi[19]*/ =rxmsg[92];
		split_int.byte[1] /*= hmi[20]*/ =rxmsg[93];
		split_int.byte[0] /*= hmi[21]*/ =rxmsg[94]; //ENERGY

		energy = (uint32_t)(split_int.dfloat*100);///10;

		if(OCPP.under_voltage > charger_status_G1.voltage)
			{
				charger_status_G1.error = UnderVoltage;
			}
			else if(OCPP.over_voltage < charger_status_G1.voltage)
			{
				charger_status_G1.error = OverVoltage;
			}
			else if(OCPP.over_current_AC02 < charger_status_G1.current)
			{
				charger_status_G1.error = OverCurrentFailure;
			}
			else{
					if(charger_status_G1.error == UnderVoltage || charger_status_G1.error == OverVoltage )
					{
						charger_status_G1.error = NoError_ChargerPoint;
					}
			}
			///////////////////////////////////////////////////////////////////////////////////////

			if(charger_status_G1.charging_status == Charging_ChargerPoint)
			{
				charger_status_G1.energy =  (unsigned long int)energy - (unsigned int)charger_status_G1.start_energy;
			}
			else
			{
				charger_status_G1.energy = 0;
			}
		charger_status_G1.hmi[0] = 0x5a;
		charger_status_G1.hmi[1] = 0xa5;
		charger_status_G1.hmi[2] = 19;
		charger_status_G1.hmi[3] = 0x82;
		charger_status_G1.hmi[4] = 0x10;
		charger_status_G1.hmi[5] = 0x00;

		split_int.dword = (charger_status_G1.voltage*10000);

		charger_status_G1.hmi[6] = split_int.byte[3];
		charger_status_G1.hmi[7] = split_int.byte[2];
		charger_status_G1.hmi[8] = split_int.byte[1];
		charger_status_G1.hmi[9] = split_int.byte[0]; //Voltage

		split_int.dword = (charger_status_G1.current*10000);
		charger_status_G1.hmi[10] = split_int.byte[3];
		charger_status_G1.hmi[11] = split_int.byte[2];
		charger_status_G1.hmi[12] = split_int.byte[1];
		charger_status_G1.hmi[13] = split_int.byte[0]; //current


		split_int.dword = (charger_status_G1.power*10000);
		charger_status_G1.hmi[14] = split_int.byte[3];
		charger_status_G1.hmi[15] = split_int.byte[2];
		charger_status_G1.hmi[16] = split_int.byte[1];
		charger_status_G1.hmi[17] = split_int.byte[0]; //power

		split_int.dword = charger_status_G1.energy;
		charger_status_G1.hmi[18] = split_int.byte[3];
		charger_status_G1.hmi[19] = split_int.byte[2];
		charger_status_G1.hmi[20] = split_int.byte[1];
		charger_status_G1.hmi[21] = split_int.byte[0]; //KWh
		}

	}
#endif
	else if(modbus_device_addr==0x02)
		{
		if((temparray[0] == rxmsg[35] ) &&  (temparray[1] == rxmsg[36]))
			{
			enrgyread2_timouttick=5000;
			charger_status_G2.hmi[0] = 0x5a;
			charger_status_G2.hmi[1] = 0xa5;
			charger_status_G2.hmi[2] = 19;
			charger_status_G2.hmi[3] = 0x82;
			charger_status_G2.hmi[4] = 0x10;
			charger_status_G2.hmi[5] = 0x00;

			split_int.byte[3] = charger_status_G2.hmi[6] =rxmsg[3];
			split_int.byte[2] = charger_status_G2.hmi[7] =rxmsg[4];
			split_int.byte[1] = charger_status_G2.hmi[8] =rxmsg[5];
			split_int.byte[0] = charger_status_G2.hmi[9] =rxmsg[6]; //VOLTAGE
			charger_status_G2.voltage = split_int.dword/10000;

			split_int.byte[3] = charger_status_G2.hmi[10] =rxmsg[7];
			split_int.byte[2] = charger_status_G2.hmi[11] =rxmsg[8];
			split_int.byte[1] = charger_status_G2.hmi[12] =rxmsg[9];
			split_int.byte[0] = charger_status_G2.hmi[13] =rxmsg[10]; //CURRENT
			charger_status_G2.current = (float)split_int.dword/10000;

			split_int.byte[3] = charger_status_G2.hmi[14] =rxmsg[11];
			split_int.byte[2] = charger_status_G2.hmi[15] =rxmsg[12];
			split_int.byte[1] = charger_status_G2.hmi[16] =rxmsg[13];
			split_int.byte[0] = charger_status_G2.hmi[17] =rxmsg[14]; //KW
			charger_status_G2.power = (float)split_int.dword/10000;

			split_int.byte[3] /*= hmi[18]*/ =rxmsg[15];
			split_int.byte[2] /*= hmi[19]*/ =rxmsg[16];
			split_int.byte[1] /*= hmi[20]*/ =rxmsg[17];
			split_int.byte[0] /*= hmi[21]*/ =rxmsg[18]; //ENERGY

			energy2 = (uint32_t)split_int.dword/10;

			if(OCPP.under_voltage > charger_status_G2.voltage && (powerfailure_flag!=5))
			{
				charger_status_G2.error = UnderVoltage;

			}
			else if(OCPP.over_voltage < charger_status_G2.voltage)
			{
				charger_status_G2.error = OverVoltage;

			}
			else if(OCPP.over_current_AC02 < charger_status_G2.current)
			{
				charger_status_G2.error = OverCurrentFailure;

			}
			else if(charger_status_G2.error == GroundFailure)
			{

			}
			else if(charger_status_G2.error == PowerSwitchFailure)
			{

			}
			else if(charger_status_G2.error == InternalError)
			{

			}
			else
			{
				//////////////////////////////////////V3.3.1///////////////////////////////
				if(charger_status_G2.stop == Error ||  charger_status_G2.charging_status == Faulted_ChargerPoint)
				{
					charger_status_G2.stop = Stoped;
					enQueue(G2_StatusNotification);
					gun_2 = G_NoError;
					 if(Ocpp_Setting.Operative[2] == Available_ChargerPoint)
					  {
						 charger_status_G2.charging_status = Available_ChargerPoint;
					  }
					  else if(Ocpp_Setting.Operative[2] == Unavailable_ChargerPoint)
					  {
						  charger_status_G2.charging_status = Unavailable_ChargerPoint;
					  }
					//charger_status_G2.charging_status = Available_ChargerPoint;
				}
				charger_status_G2.error = NoError_ChargerPoint;
			}

			if((charger_status_G2.error == UnderVoltage) || (charger_status_G2.error == OverVoltage) || (charger_status_G2.error == OverCurrentFailure) || (charger_status_G2.error == GroundFailure) || (charger_status_G2.error == PowerSwitchFailure) || (charger_status_G2.error == InternalError)||(charger_status_G2.error == OtherError) || charger_status_G2.error == InternalError)
			{
				if(charger_status_G2.start == Started)
				{
					charger_status_G2.stop = Try_To_Stop;
					gun_2 = G_Discharging;
				}
				else if(charger_status_G2.charging_status != Faulted_ChargerPoint)
				{
					gun_2 = G_Error;
					enQueue(G2_StatusNotification);
				}

				charger_status_G2.stop =Error;
				charger_status_G2.charging_status = Faulted_ChargerPoint;
				if(charger_status_G2.error != PowerSwitchFailure)			//V4.x.8
				{
				charger_status_G2.reson= Other;
				}
			}
			///////////////////////////////////////////////////////////////////////////////////////

			if(charger_status_G2.charging_status == Charging_ChargerPoint)
			{
				charger_status_G2.energy =  (uint32_t)energy2 - charger_status_G2.start_energy;
			}
			else
			{
				charger_status_G2.energy = 0;
			}

			split_int.dword = charger_status_G2.energy;
			charger_status_G2.hmi[18] = split_int.byte[3];
			charger_status_G2.hmi[19] = split_int.byte[2];
			charger_status_G2.hmi[20] = split_int.byte[1];
			charger_status_G2.hmi[21] = split_int.byte[0]; //KWh
			}
		}

#ifdef GUN3
	else if(modbus_device_addr==0x03)
	{
		enrgyread3_timouttick=5000;
		 energymeter_err[3] = 0;
		charger_status_G3.hmi[0] = 0x5a;
		charger_status_G3.hmi[1] = 0xa5;
		charger_status_G3.hmi[2] = 19;
		charger_status_G3.hmi[3] = 0x82;
		charger_status_G3.hmi[4] = 0x10;
		charger_status_G3.hmi[5] = 0x00;

		split_int.byte[3] = charger_status_G3.hmi[6] =rxmsg[3];
		split_int.byte[2] = charger_status_G3.hmi[7] =rxmsg[4];
		split_int.byte[1] = charger_status_G3.hmi[8] =rxmsg[5];
		split_int.byte[0] = charger_status_G3.hmi[9] =rxmsg[6]; //VOLTAGE
		charger_status_G3.voltage = split_int.dword/10000;

		split_int.byte[3] = charger_status_G3.hmi[10] =rxmsg[7];
		split_int.byte[2] = charger_status_G3.hmi[11] =rxmsg[8];
		split_int.byte[1] = charger_status_G3.hmi[12] =rxmsg[9];
		split_int.byte[0] = charger_status_G3.hmi[13] =rxmsg[10]; //CURRENT
		charger_status_G3.current = (float)split_int.dword/10000;

		split_int.byte[3] = charger_status_G3.hmi[14] =rxmsg[11];
		split_int.byte[2] = charger_status_G3.hmi[15] =rxmsg[12];
		split_int.byte[1] = charger_status_G3.hmi[16] =rxmsg[13];
		split_int.byte[0] = charger_status_G3.hmi[17] =rxmsg[14]; //KW
		charger_status_G3.power = (float)split_int.dword/10000;

		split_int.byte[3] /*= hmi[18]*/ =rxmsg[15];
		split_int.byte[2] /*= hmi[19]*/ =rxmsg[16];
		split_int.byte[1] /*= hmi[20]*/ =rxmsg[17];
		split_int.byte[0] /*= hmi[21]*/ =rxmsg[18]; //ENERGY

		energy3 = (uint32_t)split_int.dword/10;

		if(OCPP.under_voltage > charger_status_G3.voltage && (powerfailure_flag!=5))
		{
			charger_status_G3.error = UnderVoltage;

		}
		else if(OCPP.over_voltage < charger_status_G3.voltage)
		{
			charger_status_G3.error = OverVoltage;

		}
		else if(OCPP.over_current_AC02 < charger_status_G3.current)
		{
			charger_status_G3.error = OverCurrentFailure;
		}
		else if((charger_status_G3.error == GroundFailure))
		{

		}
		else if(charger_status_G3.error == PowerSwitchFailure)
		{

		}
		else if(charger_status_G3.error == InternalError)
		{

		}
		else
		{
			//////////////////////////////////////V3.3.1///////////////////////////////
			if(charger_status_G3.stop == Error)
			{
				charger_status_G3.stop = Stoped;
				enQueue(G3_StatusNotification);
				gun_3 = G_NoError;

				//charger_status_G3.charging_status = Available_ChargerPoint;
				 if(Ocpp_Setting.Operative == Available_ChargerPoint)
				  {
					 charger_status_G3.charging_status = Available_ChargerPoint;
				  }
				  else if(Ocpp_Setting.Operative == Unavailable_ChargerPoint)
				  {
					  charger_status_G3.charging_status = Unavailable_ChargerPoint;
				  }
			}
			charger_status_G3.error = NoError_ChargerPoint;
		}

		if((charger_status_G3.error == UnderVoltage) || (charger_status_G3.error == OverVoltage) || (charger_status_G3.error == OverCurrentFailure) || (charger_status_G3.error == GroundFailure) || (charger_status_G3.error == PowerSwitchFailure) || (charger_status_G3.error == InternalError)||(charger_status_G3.error == OtherError) || charger_status_G3.error == InternalError)
		{
			if(charger_status_G3.start == Started)
			{
				charger_status_G3.stop = Try_To_Stop;
				gun_3 = G_Discharging;
			}
			else if(charger_status_G3.charging_status != Faulted_ChargerPoint)
			{
				gun_3 = G_Error;
				enQueue(G3_StatusNotification);
			}

			charger_status_G3.stop =Error;
			charger_status_G3.charging_status = Faulted_ChargerPoint;
			charger_status_G3.reson= Other;
		}
		///////////////////////////////////////////////////////////////////////////////////////
		if(charger_status_G3.charging_status == Charging_ChargerPoint)
		{
			charger_status_G3.energy =  (uint32_t)energy3 - charger_status_G3.start_energy;
		}
		else
		{
			charger_status_G3.energy = 0;
		}

		split_int.dword = charger_status_G3.energy;
		charger_status_G3.hmi[18] = split_int.byte[3];
		charger_status_G3.hmi[19] = split_int.byte[2];
		charger_status_G3.hmi[20] = split_int.byte[1];
		charger_status_G3.hmi[21] = split_int.byte[0]; //KWh
	}
#endif
	if(OCPP.under_voltage > charger_status_G1.voltage && (powerfailure_flag!=5))
	{
		charger_status_G1.error = UnderVoltage;

	}
	else if(OCPP.over_voltage < charger_status_G1.voltage)
	{
		charger_status_G1.error = OverVoltage;

	}
	else if(OCPP.over_current_AC02 < charger_status_G1.current)
	{
		charger_status_G1.error = OverCurrentFailure;

	}
	else if(charger_status_G1.error == GroundFailure)
	{

	}
	else if(charger_status_G1.error == PowerSwitchFailure)
	{

	}
	else if(charger_status_G1.error == InternalError)
	{

	}
	else
		 {
			//////////////////////////////////////V3.3.1///////////////////////////////
			if(charger_status_G1.stop == Error || charger_status_G1.charging_status == Faulted_ChargerPoint )
			{
				charger_status_G1.stop = Stoped;
				enQueue(G1_StatusNotification);
				gun_1 = G_NoError;

				if(Ocpp_Setting.Operative[1] == Available_ChargerPoint)
				  {
					 charger_status_G1.charging_status = Available_ChargerPoint;
				  }
				  else if(Ocpp_Setting.Operative[1] == Unavailable_ChargerPoint)
				  {
					  charger_status_G1.charging_status = Unavailable_ChargerPoint;
				  }

			}
			charger_status_G1.error = NoError_ChargerPoint;
		}

		if((charger_status_G1.error == UnderVoltage) || (charger_status_G1.error == OverVoltage) || (charger_status_G1.error == OverCurrentFailure) || (charger_status_G1.error == InternalError) || (charger_status_G1.error == GroundFailure ))
		{
			if(charger_status_G1.start == Started)
			{
				charger_status_G1.stop = Try_To_Stop;
				gun_1 = G_Discharging;
			}
			else if(charger_status_G1.charging_status != Faulted_ChargerPoint)
			{
				gun_1 = G_Error;
				enQueue(G1_StatusNotification);
			}

			charger_status_G1.stop =Error;
			charger_status_G1.charging_status = Faulted_ChargerPoint;
			if(charger_status_G1.error != PowerSwitchFailure)			//V4.x.8
			{
			charger_status_G1.reson= Other;
			}
		}
		///////////////////////////////////////////////////////////////////////////////////////

		if(charger_status_G1.charging_status == Charging_ChargerPoint)
		{
			charger_status_G1.energy =  (unsigned long int)energy - (unsigned int)charger_status_G1.start_energy;
		}
		else
		{
			charger_status_G1.energy = 0;
		}
#endif
}
/**
 * @brief Perform energy meter read/write operations.
 *
 * This function sends commands to the energy meter via UART based on the specified operation.
 *
 * @param[in] rw Operation type:
 *            - 1: Write command for Meter 1 (sends the query for meter 1).
 *            - 2: Write command for Meter 2 (sends the query for meter 2).
 *            - 3: Write command for Meter 3 (sends the query for meter 3).
 *            - 4: Write command to clear accumulated energy for Meter 1.
 *            - 5: Write command to clear accumulated energy for Meter 2.
 *            - 6: Write command to clear accumulated energy for Meter 3.
 *
 *@return NA
 */
void Energy_MeterRead(char rw)
{
	uint8_t buff[12];//={0x5a,0xa5,0x05,0x82,0x00,0x0a,0x00,0x01,0x0a,0x0d};
#if meter == selec
	if(rw == 1)
	{	//for selec meter
		buff[0]=0x01;
		buff[1]=0x04;
		buff[2]=0x00;
		buff[3]=0x0E; // AVERAGE VOLTAGE //06 average voltage LN
		buff[4]=0x00;
		buff[5]=0x2E; // 2E FOR LL//0x02 // 36 FOR LN
		buff[6]=0x11; // 0x11 //90 // FOR LL
		buff[7]=0xD5;// 0xD5 // 1D // FOR LL

		HAL_UART_Transmit(&huart1, (uint8_t*)buff,8,0xffff);
		// __HAL_UART_FLUSH_DRREGISTER(&huart1);
		//HAL_UART_Receive_DMA(&huart1,(uint8_t*)rxmsg,97); =
		Send_meter = 1;
		 meter_failed++;
	}
#elif meter == rishabh
	if(rw == 1)
		{	//for selec meter
			buff[0]=0x01;
			buff[1]=0x04;
			buff[2]=0x00;
			buff[3]=0x02; // AVERAGE VOLTAGE //06 average voltage LN
			buff[4]=0x00;
			buff[5]=0x02; // 2E FOR LL//0x02 // 36 FOR LN
			buff[6]=0xD0; // 0x11 //90 // FOR LL
			buff[7]=0x0B;// 0xD5 // 1D // FOR LL

			HAL_UART_Transmit(&huart1, (uint8_t*)buff,8,0xffff);
			// __HAL_UART_FLUSH_DRREGISTER(&huart1);
			//HAL_UART_Receive_DMA(&huart1,(uint8_t*)rxmsg,97); =
			Send_meter = 1;
		}
#else

	if(rw == 1)
	{
		buff[0]=0x01;
		buff[1]=0x03;
		buff[2]=0x00;
		buff[3]=0x48; //write
		buff[4]=0x00;
		buff[5]=0x08;
		buff[6]=0xC4;
		buff[7]=0x1A;
		HAL_UART_Transmit(&huart1, (uint8_t*)buff,8,0xffff);
		// __HAL_UART_FLUSH_DRREGISTER(&huart1);
		//HAL_UART_Receive_DMA(&huart1,(uint8_t*)rxmsg,97); =
		Send_meter = 1;
	}
#endif
	else if(rw == 2)
	{
		buff[0]=0x02;
		buff[1]=0x03;
		buff[2]=0x00;
		buff[3]=0x48; //write
		buff[4]=0x00;
		buff[5]=0x08;
		buff[6]=0xC4;
		buff[7]=0x29;
		HAL_UART_Transmit(&huart1, (uint8_t*)buff,8,0xffff);
		Send_meter = 2;
	}
	else if(rw == 3)
	{
		buff[0]=0x03;
		buff[1]=0x03;
		buff[2]=0x00;
		buff[3]=0x48; //write
		buff[4]=0x00;
		buff[5]=0x08;
		buff[6]=0xC5;
		buff[7]=0xf8;
		HAL_UART_Transmit(&huart1, (uint8_t*)buff,8,0xffff);
	}
#if meter == normal
	else if(rw == 4)
	{
		buff[0]=0x01;
		buff[1]=0x10;
		buff[2]=0x00;
		buff[3]=0x4B; //write 0 yn to kwh
		buff[4]=0x00;
		buff[5]=0x02;
		buff[6]=0x04;
		buff[7]=0x00;
		buff[8]=0x00;
		buff[9]=0x00;
		buff[10]=0x00;
		buff[11]=0xB6;
		buff[12]=0x2C;
		HAL_UART_Transmit(&huart1, (uint8_t*)buff,13,0xffff);
		meter1whclear=0;
	}
	else if(rw == 5)
	{
		buff[0]=0x02;
		buff[1]=0x10;
		buff[2]=0x00;
		buff[3]=0x4B; //write 0 INK
		buff[4]=0x00;
		buff[5]=0x02;
		buff[6]=0x04;
		buff[7]=0x00;
		buff[8]=0x00;
		buff[9]=0x00;
		buff[10]=0x00;
		buff[11]=0xB9;
		buff[12]=0x68;
		HAL_UART_Transmit(&huart1, (uint8_t*)buff,13,0xffff);
		meter2whclear=0;
	}
#endif
}
/**
 * @brief Sends a meter query based on the given type.
 *
 * @param M_send Type of meter query to send.
 * @return None
 */
void Send_Meterquery(unsigned char M_send)
{
	switch(M_send)
	{
	case M1_IV :
					make_query(1,4,14,10);
					break;
	case M2_IV  :
					make_query(2,4,14,10);
					break;
	case M1_KW :
					make_query(1,4,42,2);
					break;
	case M2_KW  :
					make_query(2,4,42,2);
					break;
	case M1_KWH :
					make_query(1,4,88,2);
					break;
	case M2_KWH  :
					make_query(2,4,88,2);
					break;
	};

}
/**
 * @brief Constructs a query message based on parameters and sends it via UART.
 *
 * @param id Meter ID.
 * @param FC Function code.
 * @param addr Address.
 * @param n_byte Number of bytes.
 * @return None
 */
void make_query(unsigned char id,unsigned char FC,unsigned int addr,unsigned int n_byte)
{
	unsigned char msg[10] = {0};
	unsigned int lclCRCchk;

	msg[0] = id;
	msg[1] = FC;
	msg[2] = (addr >> 8);
	msg[3] = (uint8_t)addr;
	msg[4] = (n_byte >> 8);
	msg[5] = (uint8_t)(n_byte);
	lclCRCchk = ModCRC(msg,6);
	msg[6] = (uint8_t)lclCRCchk;
    msg[7] = (lclCRCchk >> 8);
    HAL_UART_Transmit(&huart1, (uint8_t*)msg,8,0xffff);
}
/**
 * @brief Sends a Modbus exception response message.
 *
 * @param code Exception code to be included in the response.
 * @return None
 */
/*
 *
void modbus_exemtion(unsigned char code)
{
	txmsg[0]=0x01; //Address
	txmsg[1]=modbus_cmd|0x80; //Command
	txmsg[2]=code; //Exception code
	split_int.word=CRC16(txmsg,3);
	txmsg[3]=split_int.byte[0];
	txmsg[4]=split_int.byte[1];
	HAL_UART_Transmit_DMA(&huart1, (uint8_t*)txmsg, 5);
}
*/
