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.
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?db.print("R ID=");
there is a space inside your url. Urls shouldn't contain spaces.