#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>

#define MAXWAIT 500  //Max time to wait for response between messages
#define MAXMESSAGELEN 60 //Maxiumum message length
const char *ssid = "SBX";
const char *password = "leftturn";

const int redButtonPin = 12;    // Red button connected to D12
const int greenButtonPin = 33;  // Green button connected to D33
const int blueButtonPin = 32;   // Blue button connected to D32

const int redLEDPin = 27;       // Red LED pin connected to D27
const int greenLEDPin = 26;     // Green LED pin connected to D26
const int blueLEDPin = 25;      // Blue LED pin connected to D25

// Sensor data structure
struct ModBusRequest {
  char operation[40];
  int PDU;
  int address;
  int hex;
  int length;
  bool negative;
  bool datamode;
  bool datatype;
  int scale;
  char unit[3];

};

struct modbusData {
  uint8_t msgLength; // Message length
  uint8_t data[MAXMESSAGELEN]; // The data
  char error[40]; //Error message for result - eg CRC error
};


// Array to hold all instances of ModBusRequest
ModBusRequest ModBusRequestArray[] = {

	{"Time Year ", 4, 33022, 0x80FE, 1, false, false, true, 1, ""},
	{"Time Month", 4, 33023, 0x80FF, 1, false, false, true, 1, ""},
	{"Time Day  ", 4, 33024, 0x8100, 1, false, false, true, 1, ""},
	{"Time Hour ", 4, 33025, 0x8101, 1, false, false, true, 1, ""},
	{"Time Min  ", 4, 33026, 0x8102, 1, false, false, true, 1, ""},
	{"Time Sec  ", 4, 33027, 0x8103, 1, false, false, true, 1, ""},
	{"Product Mode", 4, 33000, 0x80E8, 12, false, false, true, 1, ""},
	{"Solar Power", 4, 33057, 0x8121, 2, false, false, true, 1, "W"},
	{"Inverter Power", 4, 33151, 0x817F, 2, true, false, true, 1, "W"},
	{"Active Power", 4, 33079, 0x8137, 2, true, false, true, 1, "W"},
	{"Meter Power ", 4, 33130, 0x816A, 2, true, false, true, 1, "W"},
	{"House Power", 4, 33147, 0x817B, 1, false, false, true, 1, "W"},
	{"Battery Power", 4, 33149, 0x817D, 2, true, false, true, 1, "W"},
	{"Batt Dirn (OUT = 1) ", 4, 33135, 0x816F, 1, false, false, true, 1, ""},
	{"Battery Charge Value", 4, 33139, 0x8173, 1, false, false, true, 1, "%"},
	{"Battery Health Value", 4, 33140, 0x8174, 1, false, false, true, 1, "%"},
    {"Inverter Temperature", 4, 33093, 0x8145, 1, true, false, true, 10, "C"}
};
ModBusRequest opTest [] = {
	{"Just Testing ", 4, 33022, 0x80FE, 1, false, false, true, 1, "X"}
	};



#include "form.h"

modbusData outmsg;
modbusData results[20] ;


int swapBytes(int value) {
  // Use bitwise operations to swap the bytes
  value = ((value >> 8) & 0xFF) | ((value << 8) & 0xFF00);
  return value;
}

String byteArrayToHexString(byte* b, size_t blen) {
  String result = "";
  for (size_t i = 0; i < blen; i++) {
    // Convert each byte to a two-digit hex string
    char hexString[4];
    sprintf(hexString, " %02X", b[i]);
    // Concatenate the hex string to the result
    result += hexString;
  }
  return result;
}

// Function to calculate Modbus RTU CRC
uint16_t calculateModbusCRC(const char* data, int len) {
  uint16_t crc = 0xFFFF; // Initial value

  for (int i = 0; i < len; i++) {
    crc ^= static_cast<uint8_t>(data[i]); // XOR with current byte

    for (int j = 0; j < 8; j++) {
      if (crc & 0x0001) {
        crc = (crc >> 1) ^ 0xA001; // Right shift and XOR with polynomial
      } else {
        crc = crc >> 1; // Right shift
      }
    }
  }
  return crc;
}

// Function to calculate Modbus RTU CRC
uint16_t calculateModbusCRC(const byte* data, int len) {
  uint16_t crc = 0xFFFF; // Initial value

  for (int i = 0; i < len; i++) {
    //Serial.println(data[i],HEX);
    crc ^= static_cast<uint8_t>(data[i]); // XOR with current byte

    for (int j = 0; j < 8; j++) {
      if (crc & 0x0001) {
        crc = (crc >> 1) ^ 0xA001; // Right shift and XOR with polynomial
      } else {
        crc = crc >> 1; // Right shift
      }
    }
  }
  return crc;
}

void makeMsg(const ModBusRequest& sd, modbusData& msg) {
  msg.data[0] = 0x1;
  msg.data[1] = sd.PDU;
  msg.data[2] = sd.hex >> 8;
  msg.data[3] = sd.hex & 0xff;
  msg.data[4] = 0;
  msg.data[5] = sd.length;
  //Now need to get the checksum
  msg.msgLength = 8 ; //Includes checksum
  int crc = calculateModbusCRC((const char*) msg.data, msg.msgLength - 2);
  msg.data[6] = crc & 0xff;
  msg.data[7] = crc >> 8;
}

void listMsg(modbusData msg) {
  for (int j = 0; j < msg.msgLength; ++j) {
    if (msg.data[j] < 16 ) {
      Serial.print("0");
    }
    Serial.print(msg.data[j], HEX);
    Serial.print(" ");
  }
  Serial.println("");
}

// Function to send Modbus RTU queries
void sendModbusQueries( ModBusRequest ModBusRequestArray[], size_t arraySize) {
	
	Serial.print( "Processing "); Serial.print( arraySize); Serial.println( "Requests. ");
	
  for (size_t i = 0; i < arraySize; ++i) {
    delay(20);
    //3. Red light on start of each sub-requests
    digitalWrite(redLEDPin, HIGH);
    digitalWrite(blueLEDPin, LOW);
    makeMsg(ModBusRequestArray[i], outmsg);
    Serial.print("Query for ");
    Serial.print(ModBusRequestArray[i].operation);
    Serial.println(": ");
    listMsg(outmsg);
    Serial2.write(outmsg.data, outmsg.msgLength);


    //============================
    // Check if there is data available on Serial2
    long timeToRespond  = millis();
    //Allow some time for response
    while (Serial2.available() == 0) {
      if (millis() - timeToRespond > MAXWAIT) {
        Serial.println("No reply.");
        break;
      }
      delay(2);
    }
    timeToRespond = millis() - timeToRespond ;

    // Read incoming data while available
    int index = 0;
    while (Serial2.available() > 0) {
      byte rx  = Serial2.read();
      results[i].data[index++] = rx;
      Serial.print(" RX =>"); Serial.println(rx, HEX);
      // Check for buffer overflow
      if (index >= MAXMESSAGELEN) {
        break;
      }
    }
    // Store the length of the result
    results[i].msgLength = static_cast<uint8_t>(index);
	
    if (index == 0 ) { //No data received
      //Create dummy test data
      results[i].data[0] = 0x01;
      results[i].data[1] = 0x04;
      int len = ModBusRequestArray[i].length * 2;
      results[i].data[2] = len;
      int z = 0;
      for (z = 3; z < len + 3; z += 2) {
        //Create dummy result
        if (len == 4 && z <  5 ) {
          results[i].data[z] = 0;
        } else {
          results[i].data[z] = 0;
          results[i].data[z + 1] = z + i;
        }
      }
      results[i].msgLength = len + 5;
      int crc = calculateModbusCRC((const char*) results[i].data, results[i].msgLength - 2);
      results[i].data[3 + len] = crc & 0xff;
      results[i].data[4 + len ] = crc >> 8;
    } else {
      //Data was received
      digitalWrite(blueLEDPin, HIGH);
    }
	
	//Calculate checksum of response
	int calcCRC= calculateModbusCRC((const char*)  results[i].data,  results[i].msgLength - 2);
	int crcLocn = results[i].msgLength - 2;
	int inCRC = results[i].data[crcLocn +1 ] << 8 + results[i].data[crcLocn];
	
	if (inCRC != calcCRC){
		 Serial.println("CRC Mismatch. ");
		 Serial.print("Recvd:");Serial.print(inCRC,HEX); 
		 Serial.print("Calc :");Serial.println(calcCRC,HEX); 
		 strcpy(results[i].error, "CRC error");
		 //Add data to the message structure
	} else {
		 Serial.println("CRC OK ");
		 strcpy(results[i].error, "");
	}
	
    Serial.print("Result Length: ");
    Serial.print(results[i].msgLength);

    Serial.print(" Result: ");
    listMsg(results[i]);

    digitalWrite(redLEDPin, LOW);
  }
} //end sendModbusQueries


// Function to decode the response data
String decodeResponse(uint8_t *responseData, int dataLength, int scale) {
  String decodedResult = "";
  int rlen = responseData[2];
  
  if (rlen>4){ //Just return hex data values
	String hexString = "";  // Clear the output hex string
	  // Loop through each character in the input string
	  for (int i = 0; i < rlen; ++i) {
		// Convert the current character to its hexadecimal representation
		char hexBuffer[4];
		snprintf(hexBuffer, sizeof(hexBuffer), " %02X", static_cast<unsigned char>(responseData[i]));

		// Append the hexadecimal representation to the output hex string
		hexString += hexBuffer;
	  }
	  
	 return hexString;
  }
  
  for (int i = 0; i < rlen; i += 2) {
    // Combine two bytes into a one
    // Byte order H,L
    long value =  (responseData[i + 3] << 8) + responseData[i + 4] ;
    if (rlen == 4 ) {
      value += (responseData[i + 5] << 8) + responseData[i + 6] + (value << 16) ;
      i += 2; //double increment i
    }

//Some items are scaled like temperature - correct scaling now
    if (scale != 1) {
		float avalue = (0.0 + value) / scale;
		decodedResult += String(avalue);
	} else {
		// Convert the integer to a string and append to the result
		decodedResult += String(value);
	}

    // If there are more pairs, separate them by commas
    if (i + 2 < responseData[2]) {
      decodedResult += ", ";
    }
    //Serial.println(decodedResult);
  }


  return decodedResult;
}

String makeHTML() {

  // Construct HTML table
  String htmlTable = "<table border='1'>\n<tr><th>Operation</th><th>Data</th><th>Length</th></tr>";

  for (int i = 0; i < sizeof(ModBusRequestArray) / sizeof(ModBusRequestArray[0]); i++) {
    // Assuming results[i].data contains the response data
	int totalLength = results[i].msgLength;
    int responseDataLength = results[i].data[2]; // Response data length
	int scale = ModBusRequestArray[i].scale;
    // Decode response data
    String decodedData = decodeResponse(results[i].data, responseDataLength,scale);

    htmlTable += "\n<tr><td>" + String(ModBusRequestArray[i].operation) + \
				"</td><td>" + decodedData  + String(ModBusRequestArray[i].unit) + \
				"</td><td>"+String(totalLength) +" " + String(results[i].error) +"</td></tr>";
  }

  htmlTable += "\n</table>";

  // Print the HTML table to Serial
  Serial.println(htmlTable);

  // You can also send this HTML table to a web server or display it on a web page, depending on your application.
  return htmlTable;
}
WebServer server(80);

const int led = 2;

//Convert String parameter to Int
int toInt(String x){
	  return x.toInt();
  }
  
void TXtest (){
  Serial.println("\nRunning TXtest");
	  
  String message = R"XX(<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Solis Info</title>
 <style>
    body { background-color: #ffffff; font-family: Arial, Helvetica, Sans-Serif;}
</style>	
<H1>Solis Test </H1>
  )XX";
  
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n<P>";

  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  message += "\n\n<P>";
  
/*
// Sensor data structure
struct ModBusRequest {
  char operation[40];
  int PDU;
  int address;
  int hex;
  int length;
  bool negative;
  bool datamode;
  bool datatype;
  int scale;
  char unit[3];

};
ModBusRequest opTest [] = {
	{"Just Testing ", 4, 33022, 0x80FE, 1, false, false, true, 1, "X"}
	};
	
	URI: /test
Method: POST
Arguments: 4
0 name: check
1 prefix: 02
2 number: 12345
3 size: 2
*/

//Build up the values in a Simple String
byte b[8];
	String temp;
	b[0] = 0x1; //Client address
	b[1] =  toInt(server.arg(1)); //Modbus request type
	int number = toInt(server.arg(2)); //Number of the request (entered in decimal)
	b[2] = number >> 8; //High byte
	b[3] = number & 0xff; //low byte
	b[4] = 0; //Upper length indicator  - always 0
	b[5] = toInt(server.arg(3)); //Expected Number of words in response Usually 1 or 2 
	// Calculate check sum on b[0] to b[5]
	int CRC = calculateModbusCRC(b, 6);
	b[6] = CRC & 0xff;
	b[7] = CRC >> 8;
	String hexString= byteArrayToHexString(b,8);
	Serial.print(hexString);
	message += "Sending: " + hexString;
	
  server.send(200, "text/html", message);
  return;
  

  
//Now create a request based on the input with an added checksum


	Serial.print ("\n\nCreating message:");	Serial.println (server.arg(0));
	Serial.print ("Hex:"); 				Serial.println(server.arg(1));

	String myhtml= "<h1> "+ server.arg(0) + "  " + server.arg(1) + "<h1><P>\n";
	/*
	  char operation[40];
  int PDU;
  int address;
  int hex;
  */
	//Build up request
	

	
	
	digitalWrite(greenLEDPin, LOW);
  //Create response table
  String table = makeHTML();
  //return response
  String out = R"XX(<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="refresh" content="10" >
    <title>Solis Info</title>
 <style>
      body { background-color: #ffffff; font-family: Arial, Helvetica, Sans-Serif;}
/* Style for the table */
table {
  border-collapse: collapse;
}
/* Style for the table header (first row) */
table th {
  background-color: #4CAF50; /* Green color for the header row */
  color: white;
  padding: 12px;
  text-align: left;
}
/* Style for alternating rows */
table tr:nth-child(even) {
  background-color: #f1f1f1; /* Light green color for even rows */
}
table tr:nth-child(odd) {
  background-color: white; /* White color for odd rows */
}
/* Style for table cells */
table td {
  padding: 8px;
  border: 1px solid #ddd;
}
    </style>
  </head>
    <body>
    <h1>Solis Info</h1>
  )XX";
  
  out += table;
  out += "<P></body>";

  server.send(200, "text/html", out);


	

}

void handleRoot() {
	 info();
}

void showForm(){
	Serial.println("======= Test form display ==========");
  digitalWrite(led, 1);

/*
  const char * myhtml =  R"XX(<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Solis Test</title>
    <style>
    body {
      font-family: Arial, sans-serif;
      background-color: #f4f4f4;
      margin: 50;
      padding: 50;
      height: 100vh;
    }

    form {
      background-color: #fff;
      padding: 40px;
      border-radius: 8px;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
      max-width: 400px;
      width: 100%;
    }

    label {
      display: block;
      margin-bottom: 8px;
    }

    input {
      width: 100%;
      padding: 8px;
      margin-bottom: 16px;
      box-sizing: border-box;
    }

    button {
      padding: 30px;
      background-color: #4caf50;
      color: #fff;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }

    button.cancel {
      background-color: #f44336;
    }
  </style>
</head>
<body>
 <h1>Solis Test</h1>
  <form action="/TXtest" method="post">
    <label for="name">Name:</label>
    <input type="text" id="name" name="name" required>

    <label for="hexdata">Hex Data:</label>
    <input type="text" id="hexdata" name="hexdata" required>

    <button type="submit">Submit</button>
    <button type="button" class="cancel">Cancel</button>
  </form>
  </body></html>)XX";
  */

  server.send(200, "text/html", myhtml);
  
  digitalWrite(led, 0);
}

void showParams() {
  digitalWrite(led, 1);
  String message = "<h2>Parameters </h2><P>";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";

  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }

  server.send(404, "text/plain", message);
  Serial.print(message);
  digitalWrite(led, 0);
}

void listParameters(String message) {
  digitalWrite(led, 1);
  message += "\n\nURI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";

  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  Serial.print(message);
  //server.send(404, "text/plain", message);
  digitalWrite(led, 0);


}



void setup(void) {
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);
  Serial.begin(115200);
  Serial2.begin(9600);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");

  pinMode(redButtonPin, INPUT_PULLUP);
  pinMode(greenButtonPin, INPUT_PULLUP);
  pinMode(blueButtonPin, INPUT_PULLUP);

  pinMode(redLEDPin, OUTPUT);
  pinMode(greenLEDPin, OUTPUT);
  pinMode(blueLEDPin, OUTPUT);

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  digitalWrite(led, HIGH);
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println("Started Serial2 ");

  /*
    if (MDNS.begin("esp32")) {
      Serial.println("MDNS responder started");
    }
  */
  server.on("/", handleRoot);
  //server.on("/test.svg", drawGraph);
  server.on("/inline", []() {
    server.send(200, "text/plain", "this works as well");
  });
  server.on("/info", info);
  
  server.on("/m1", sendM1);
  server.on("/check", sendText);
  server.on("/test", showForm);
  server.on("/TXtest", TXtest);
  server.onNotFound(showParams);
  server.begin();
  Serial.println("HTTP server started");

  Serial2.begin(9600); // Initialize Serial2 at 9600 baud

}

void checkButtons() {

  if (digitalRead(redButtonPin) == LOW) {
    funcRed();
  } else  if (digitalRead(greenButtonPin) == LOW) {
    funcGreen();
  } else  if (digitalRead(blueButtonPin) == LOW) {
    funcBlue();
  };

}

void funcRed() {

  digitalWrite(redLEDPin, HIGH);
  digitalWrite(greenLEDPin, LOW);
  digitalWrite(blueLEDPin, LOW);
  Serial.println("Red.");
  delay(500);
}
void funcBlue() {
  digitalWrite(blueLEDPin, HIGH);
  digitalWrite(greenLEDPin, LOW);
  digitalWrite(redLEDPin, LOW);
  Serial.println("Blue.");
  delay(500);
}
void funcGreen() {
  digitalWrite(greenLEDPin, HIGH);
  digitalWrite(redLEDPin, LOW);
  digitalWrite(blueLEDPin, LOW);
  Serial.println("Green.");
  delay(500);
}

void loop(void) {

  server.handleClient();
  // Call the checkButtons function in the loop
  checkButtons();
  delay(2);//allow the cpu to switch to other tasks
}

void sendMessage(String parm) {

  digitalWrite(redLEDPin, HIGH);
  digitalWrite(greenLEDPin, LOW);
  digitalWrite(blueLEDPin, LOW);

  digitalWrite(led, LOW);
  String out = "";
  Serial.println("Input " + parm);

  // Prepare the character array (the buffer)
  int plen =  parm.length();
  Serial.print("Parameter length "); Serial.println(plen);
  char char_array[plen + 1];
  // Copy it over
  parm.toCharArray(char_array, plen + 1);

  // char_array is a char * array that contains HEX chars eg 010434... without the CRC data (low, high)
  int bytelen = (plen + 1) / 2 + 2 ;

  byte outData[bytelen + 1];
  Serial.print("Byte array length "); Serial.println(bytelen);
  outData[bytelen + 1] = 0; //ALlow use as char string
  unHex(char_array, outData, plen);
  //outData biw contains the binary data as an array of bytes
  uint16_t CRC = calculateModbusCRC(outData, bytelen - 2); //Ignore the space for the CRC
  //Insert the CRC data into the byte array
  outData[bytelen - 2] =  CRC & 0xFF;
  outData[bytelen - 1] = (CRC >> 8) & 0xFF;


  //Now get a string showing the hex using printf
  //and output to client and log

  Serial.print("Char * CRC: "); Serial.println(CRC, HEX);

  sendToSerial(outData, bytelen);


  //Only one message allowed - this is not shown
  //server.send(200, "text/html", "Message sent<P>");

  //Only one message allowed - this is not shown
  //server.send(200, "text/html", "Sending Message to Serial 2<P>");
  //out = out + "<h2>Outgoing  message '" + server.arg(0) + "' Millis: " + String(millis()) + "</h2> <p>";
  long responseTime = checkSerial2(out);
  
  String hexOutput = "";
  // Call the function to convert the string to hex
  stringToHex(out, hexOutput);
  out = R"XX(<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RS485 Demo</title>
    <style>
      body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }
    </style>
  </head>
    <body>
    <h1>RS485 Response</h1>
  )XX";
  out += hexOutput;
  out += "<P>Took: " + String(responseTime) + " mSec </body>";

  server.send(200, "text/html", out);
  digitalWrite(led, LOW);

  digitalWrite(redLEDPin, LOW);
  digitalWrite(greenLEDPin, LOW);
  digitalWrite(blueLEDPin, LOW);
}



void sendText() {

  listParameters("=== sendText ===");
  sendMessage(server.arg(0)); //Pass a String variable containing HEX chars eg 010434... without the CRC data (low, high)
}

void sendM1() {
  String param  = "010480E8000C";
  sendMessage(param);

}

void info() {
  //1. Turn on Green LED
  digitalWrite(greenLEDPin, HIGH);
  //2. Start sending requests
  sendModbusQueries(ModBusRequestArray, sizeof(ModBusRequestArray) / sizeof(ModBusRequestArray[0]));
  //3. Turn off Green light when all requests processed.
  digitalWrite(greenLEDPin, LOW);
  //Create response table
  String table = makeHTML();
  //return response
  String out = R"XX(<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="refresh" content="10" >
    <title>Solis Info</title>
 <style>
      body { 
		  background-color: #ffffff; 
		  font-family: Arial, Helvetica, Sans-Serif;
	  }
	  
	  button {
		  padding: 30px;
		  background-color: #4caf50;
		  color: #fff;
		  border: none;
		  border-radius: 4px;
		  cursor: pointer;
    }
/* Style for the table */
table {
  border-collapse: collapse;
}
/* Style for the table header (first row) */
table th {
  background-color: #4CAF50; /* Green color for the header row */
  color: white;
  padding: 12px;
  text-align: left;
}
/* Style for alternating rows */
table tr:nth-child(even) {
  background-color: #f1f1f1; /* Light green color for even rows */
}
table tr:nth-child(odd) {
  background-color: white; /* White color for odd rows */
}
/* Style for table cells */
table td {
  padding: 8px;
  border: 1px solid #ddd;
}
    </style>
  </head>
    <body>
    <h1>Solis Info</h1>
  )XX";
  
  out += table;

 String tail =  R"ZZ(
	<P>
	<button onclick="location.href = '\';" >Refresh </button>
	<button onclick="location.href = '\test';" >Test</button>
  )ZZ";
  
  out += tail;
  server.send(200, "text/html", out  );

}


long checkSerial2(String &receivedString) {
  // Check if there is data available on Serial2
  long timeToRespond  = millis();

  //Allow some time for response
  while (Serial2.available() == 0) {
    if (millis() - timeToRespond > MAXWAIT) {
      receivedString += "0000";
      Serial.println("No reply.");
      return -1;
    }
    delay(1);
  }
  timeToRespond = millis() - timeToRespond ;
  while (Serial2.available() > 0) {
    // Read the incoming byte
    char incomingByte = Serial2.read();
    Serial.print(" RX =>"); Serial.println(incomingByte, HEX);
    // Append the incoming byte to the receivedString
    receivedString += incomingByte;

  }
  return timeToRespond;

}

void unHex(const char* inP, byte* outP, size_t len) {
  for (; len > 1; len -= 2) {
    byte val = asc2byte(*inP++) << 4;
    *outP++ = val | asc2byte(*inP++);
  }
}

byte asc2byte(char chr) {
  byte rVal = 0;
  //Serial.print("asc2Byte: ");Serial.print(chr);Serial.print(" => ");
  if (isdigit(chr)) {
    rVal = chr - '0';
  } else if (chr >= 'A' && chr <= 'F') {
    rVal = (byte) chr + 10 - 'A';
  }
  //Serial.println(rVal,HEX);
  return rVal;
}




// Function to send byte array to Serial2
void sendToSerial(const byte* data, int len) {
  // Send data bytes
  for (int i = 0; i < len; i++) {
    byte b = data[i];
    Serial.print("TX =>");
    Serial.println(b, HEX);
    Serial2.write(b);
  }

}

void test() {
  // Example usage
  //   01 04 80 E8 00 0C //Product Model returns Inverter ID (param 0C?)
  //:01 04 80 E8 00 0C 59 FB
  /*000218-Tx:01 04 80 E8 00 0C 59 FB
    000219-Rx:01041800F8000C000E000146464646464646464646464646464600
    Actual    0104183102003D0040000136303331303233323241313130303438D390
                                       3 1 0 2 3 2 2 a 1 1 0 0 4 8
    85 A4

    //Set the flag (param 0A?)
    000230-Tx:01 04 81 5B 00 0A 29 E2
    000231-Rx:01 04 14 00 00 00 04 00 00 00 01 00 00 00 04 06 08 00 00 00 00 00 00 EE EB

    //Total PV Energy
    000242-Tx:01 04 81 05 00 0A 48 30
    000243-Rx:01 04 14 00 00 00 71 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 71 21 EE
  */

  const byte data[] = {0x01, 0x04, 0x80, 0xE8, 0x00, 0x0C};
  //expected Checksum :  0x59, 0xFB
  sendToSerial( data, 6 );
}


void stringToHex(const String &inString, String &hexString) {
  hexString = "";  // Clear the output hex string

  // Loop through each character in the input string
  for (size_t i = 0; i < inString.length(); ++i) {
    // Convert the current character to its hexadecimal representation
    char hexBuffer[4];
    snprintf(hexBuffer, sizeof(hexBuffer), " %02X", static_cast<unsigned char>(inString[i]));

    // Append the hexadecimal representation to the output hex string
    hexString += hexBuffer;
  }
}