1

I have developed an application with a SunFounder Mega2560 with a W5100 Ethernet shield that acts as a server and successfully parses TCP message packets from a client sending in updates. I am now trying to add HTTP GETs into the mix by sending off my data to update an XAMPP server, which I am treating as a client in my code.

For some reason, I can't seem to connect to the XAMPP's Apache service on my machine for it to receive the HTTP message to update the MariaDB table through a PHP script I created. The Apache service seems to be listening on port 80, which I am attempting to initiate the connection on.

You can mostly just pay attention to the postData() command below, but I'm including everything for completeness.

#include <stdlib.h>
#include <string.h>
#include <SPI.h>
#include <Ethernet.h>

#define MAX_CLIENTS 1
#define MAX_LINE_LEN 100 
char inputs[MAX_CLIENTS][MAX_LINE_LEN] = {0}; // Instantiate 2D array of client/received data
int msg_array[] = {0,0,0,0};

EthernetServer server(1174);                  // Create server object on port of server, which will be used to respond to commands
EthernetClient *client = NULL;                // Create client objects limited to size of MAX_CLIENTS
EthernetClient db;                            // Create a client object just for posting HTTP commands to the database

byte mac[] = {0x24,0x0A,0xC4,0xAC,0xC1,0x78}; // Arduino's physical MAC
byte ip[] = {192,168,1,23};                   // IP of this controller 
byte gateway[] = {192,168,1,77};              // Router address (internet)
byte myDns[] = {192,168,1,77};                // Router dns
byte subnet[] = {255,255,0,0};                // Subnet mask
byte dbserver[] = {192,168,1,77};             // IP address of SQL server 

unsigned long wd_Dside, wd_Cside;             // Gather current Arduino pgm ms timestamp
unsigned long wd_Delap, wd_Celap = 0;         // Create an elapsed time counter 
int dside_prev, cside_prev = 0;       // Create a previous state for each AV to determine code execution 
char rId[3] = {0}; 
int avSide = 0; 

// --------------------------------------------------------------------------------------------------------


void setup(){

// initialize the ethernet device
//  Ethernet.begin(mac, ip, myDns, gateway, subnet);
  Ethernet.begin(mac, ip); 

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
  ; // wait for serial port to connect. Needed for native USB port only
  }

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware.");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
        }
  }

  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  pinMode(22, OUTPUT);                          // pin selected to control AV D SIDE
  pinMode(23, OUTPUT);                          // pin selected to control AV C SIDE

  // wait 5 seconds for connection:

  delay(5000);
  server.begin();                                // Start server
  Serial.print("Server started on ");
  Serial.println(Ethernet.localIP()); 
  delay(1000);

  wd_Dside, wd_Cside = millis(); 

}

// --------------------------------------------------------------------------------------------------------

void loop() {

  delay(100); 
  int i=0; 

  EthernetClient newClient = server.available(); 
  if (newClient) {
    if (client==NULL){
    client = new EthernetClient(newClient); 
  }
  }

  if (client != NULL && client->available()){                     // If the data isn't garbage and the data is available..
    Serial.print("Client's IP address: ");
    Serial.println(client->remoteIP());
    Serial.print("Client sent: ");
    char newChar = client->read();                                // Read the data  
    Serial.println(newChar); 

    if (newChar == '\0') {                                        // Check for a termination character for separation
      Serial.println("Client terminated message.");
      char delimiters[] = ",";                                    // Use a string parser in order to get command parameterization
      char* valIndex;
      valIndex = strtok(inputs[i], delimiters);
      for (int j=0; j<4; j++){                                    // Expand later to largest anticipated character count
        msg_array[j] = atoi(valIndex); 
        //Serial.print(msg_array[j]);
        valIndex = strtok(NULL, delimiters);
      }

      switch(msg_array[0]) {                                      // Determine type of message received via Ethernet (Character 0 parsed as Message Type) 

        case 3:                                                   // Examine string for instructions to turn AVs on or off. 

        char cstr[16];
        strcat(rId, itoa(msg_array[2],cstr,10));              // Build rId string prior to any potential HTTP post (which refs rId)
        strcat(rId, itoa(msg_array[3],cstr,10));
        Serial.print("R ID: ");
        Serial.println(rId); 

        if(msg_array[1] == 1)                                     // Msg type 3, Instruction 1: Turn D side AV ON
          {
            avSide = 0; 
            if (dside_prev != msg_array[1]){
              Serial.println("Dside AV is OPEN.");
              digitalWrite(22, HIGH);                             // Set pin 4 low
              postData();                                         // Call the HTTP POST function
            }

            dside_prev = msg_array[1];
            wd_Delap = 0;                                         // Reset elapsed time watchdog time value for D side. 
            wd_Dside = millis();                                  // Last good heartbeat received from client device on D side. 
          }
        if(msg_array[1] == 2)                                     // Msg type 3, Instruction 2: Turn Dside AV OFF
          {
            avSide = 0; 
            if (dside_prev != msg_array[1]){
              Serial.println("Dside AV is CLOSED.");
              digitalWrite(22, LOW);                              // Set pin 4 low
              //postData();                                         // Call the HTTP POST function
            }

            dside_prev = msg_array[1];
            wd_Delap = 0;                                         // Reset elapsed time watchdog time value for D side. 
            wd_Dside = millis();                                  // Last good heartbeat received from client device on D side. 
          } 
        if(msg_array[1] == 3)                                     // Msg type 3, Instruction 3: Turn Cside AV ON
          {
            avSide = 1; 
            if (cside_prev != msg_array[1]){
              Serial.println("Cside AV is OPEN.");
              digitalWrite(23, HIGH);                             // Set pin 5 high
              //postData();                                         // Call the HTTP POST function
            }

            cside_prev = msg_array[1];
            wd_Celap = 0;                                         // Reset elapsed time watchdog time value for C side. 
            wd_Cside = millis();                                  // Last good heartbeat received from client device on C side. 
          }
        if(msg_array[1] == 4)                                     // Msg type 3, Instruction 4: Turn Cside AV OFF
          {
            avSide = 1;
            if (cside_prev != msg_array[1]){
              Serial.println("Cside AV is CLOSED.");
              digitalWrite(23, LOW);                              // Set pin 5 high
              //postData();                                         // Call the HTTP POST function
            }

            cside_prev = msg_array[1];
            wd_Celap = 0;                                         // Reset elapsed time watchdog time value for C side. 
            wd_Cside = millis();                                  // Last good heartbeat received from client device on C side. 
          }

        rId[0]='\0';                                          // Clear the array 
        break;

        case 6:
                                                                  // Examine string for EA status messages 
        break; 

        default: 
          Serial.println("Default break encountered. Received gibberish.");
        break;

      }

    inputs[0][0] = '\0';                                      // Clear out this array element for the next message
    //client->stop();                                         // By default, kill the client session and just wait for a new TCP open
    //delete client;                                          // Remove client element's data
    //client = NULL;                                          // Reset to NULL 
    Serial.println(inputs[0]); 

    }

    else {

       if (strlen(inputs[i]) > MAX_LINE_LEN) {                     // Append it to the message content string, but first check for size compliance
        Serial.println("Max line length exceeded from client.");
        inputs[0][0] = '\0';                                       // Clear out this array element for the next message
       }
       else {
        size_t l = strlen(inputs[0]);  
        inputs[0][l] = newChar;    
        inputs[0][l + 1] = 0;
        // strcat(inputs[i], newChar);                             // Add character to the received string
       }

      Serial.print("inputs[0]: ");
      Serial.println(inputs[0]);

    }
  }

/* Update watchdog timers

wd_Delap = (millis()-wd_Dside);
wd_Celap = (millis()-wd_Cside); 

if (wd_Delap>=60000)
      {
        Serial.print("Elapsed time on watchdog, D side: ");
        Serial.println(wd_Delap);
        Serial.print("Last message recieved: ");
        Serial.println(wd_Dside);
        digitalWrite(4, LOW);    // set pin 4 low
        Serial.println("Dside AV didn't hear from anyone in 60s; defaulting to OFF.");
      } 

if (wd_Celap>=60000)
      {
        Serial.print("Elapsed time on watchdog, C side: ");
        Serial.println(wd_Celap);
        Serial.print("Last message recieved: ");
        Serial.println(wd_Cside);
        digitalWrite(5, LOW);    // set pin 5 low
        Serial.println("Cside AV didn't hear from anyone in 60s; defaulting to OFF.");
      } 
  */   
}

// Section to update database via HTTP 
void postData() {
  Serial.println("Hit postData");
  client->stop();

  delay(250);
  Serial.println("Stopping and reconnecting."); 

  if (db.connect(dbserver, 80)) {
    Serial.println("Connected to DB host machine."); 
    db.print("GET /write_data.php?");

    db.print("RID=");
    db.print(rId); 
    db.print("&");

    db.print("side=");
    db.print(avSide); 
    db.print("&");

    db.print("state=");
    db.print("1");

    db.println(" HTTP/1.1");
    db.println("Host: localhost");
    db.println("User-Agent: Arduino/1.0");
    db.println("Connection: close");
    db.println();
    db.println();
    db.stop(); 

  } 
  else {
  Serial.println("Connection failed to DB host machine.");
  }

  delay(5000);
}

This is the output:

Client's IP address: 192.168.1.77
Client sent: ,
inputs[0]: ,
Client's IP address: 192.168.1.77
Client sent: 3
inputs[0]: ,3
Client's IP address: 192.168.1.77
Client sent: ,
inputs[0]: ,3,
Client's IP address: 192.168.1.77
Client sent: 1
inputs[0]: ,3,1
Client's IP address: 192.168.1.77
Client sent: ,
inputs[0]: ,3,1,
Client's IP address: 192.168.1.77
Client sent: 3
inputs[0]: ,3,1,3
Client's IP address: 192.168.1.77
Client sent: ,
inputs[0]: ,3,1,3,
Client's IP address: 192.168.1.77
Client sent: 7
inputs[0]: ,3,1,3,7
Client's IP address: 192.168.1.77
Client sent:
Client terminated message.
R ID: 37
Dside AV is OPEN.
Hit postData
Connecting...
Connection failed to DB host machine.

Am I maybe initializing something incorrectly, or am I becoming a victim to one of the commonly references issues with the Ethernet library not being able to handle multiple connections on the Arduino?

Thanks!

EDIT: Well with some troubleshooting of the HTTP methods and formats to address the URI, I didn't turn up much; But I did by chance notice that changing my semicolons to ampersands for the value fields are what did the trick! I have achieved communication to my MariaDB! The issue I'm having now is that the client disconnects after dumping the information to the database, and does not re-enter the normal loop to wait on another message.

My postData() routine above has been edited to show what I am doing. The main loop is looping, but does not show that the server() receives anything like it would previously.

7
  • Ethernet.begin(mac, ip); for IP 192.168.1.77 assumes gateway and DNS at 192.168.1.1. use "Host: 192.168.1.77". Is the port 80 open on firewall of the PC?
    – Juraj
    Commented Aug 29, 2019 at 4:36
  • Can you reach port 80/send a POST from another machine on your network? Commented Aug 29, 2019 at 6:10
  • db.print("R ID="); there is a space inside your url. Urls shouldn't contain spaces.
    – Gerben
    Commented Aug 29, 2019 at 9:40
  • @Juraj Are you referring to a specific function that the Ethernet() library implements? I don't see a Host parameter.
    – Big Owls
    Commented Aug 29, 2019 at 19:03
  • @MarkusDeibel you and Juraj's suggestions are good ones, as I couldn't access the web page without adding a rule for all port 80, 443 and 3306 traffic; however, the code is now stepping in and attempting to connect but locks up and restarts everything.
    – Big Owls
    Commented Aug 29, 2019 at 19:44

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.