chipKIT® Development Platform

Inspired by Arduino™

chipkit mx7ck calling "hello world" from webserver

Created Tue, 22 Aug 2017 14:52:08 +0000 by aabfm


aabfm

Tue, 22 Aug 2017 14:52:08 +0000

Hi, My target is to have the mx7ck calling a php script with post arguments and read the answer from the webserver, i.e. I want to build a webclient that sends post parameters to a php script. So far I've created the a very basic program which is supposed to access Google and print via serial monitor whatever it gets but it just doesn't return anything. Here is the code based on a few examples:

#include <IM8720PHY.h>                      // This is for the the Internal MAC and SMSC 8720 PHY
#include <DEIPcK.h>

IPv4 ip = {193,0,0,171};
IPv4 subnet = {255,255,255,0};
IPv4 gatew = {193,0,0,3};

const char * server = "216.58.206.100"; // Google
unsigned short portServer = 80; 

typedef enum
{
    NONE = 0,
    CONNECT,
    WRITE,
    READ,
    CLOSE,
    DONE,
} STATE;

STATE state = CONNECT;
IPSTATUS    status;

unsigned tStart = 0;
unsigned tWait = 5000;

TCPSocket tcpClient;
byte rgbRead[1024];
int cbRead = 0;

void setup() {
  
    Serial.begin(9600);
    Serial.println("TCPEchoClient 3.0");
    Serial.println("Digilent, Copyright 2014");
    Serial.println("");

    deIPcK.begin(ip,gatew,subnet);
}

void loop() {
    int cbRead = 0;
    int contry = 1;

    switch(state)
    {
        case CONNECT:
            if(deIPcK.tcpConnect(server, portServer, tcpClient, &status))
            {
                state = WRITE;
            }
            break;

       // write out the strings  
       case WRITE:
            if(tcpClient.isEstablished())
                {     
                state = READ;
                tStart = (unsigned) millis();
                }
            break;

        case READ:

            // see if we got anything to read
            if((cbRead = tcpClient.available()) > 0)
            {
                cbRead = cbRead < sizeof(rgbRead) ? cbRead : sizeof(rgbRead);
                cbRead = tcpClient.readStream(rgbRead, 12);
                 
                for(int i=0; i < cbRead; i++) 
                {
                    Serial.print((char) rgbRead[i]);
                }
            }

            // give us some time to get everything echo'ed back
            else if( (((unsigned) millis()) - tStart) > tWait )
            {
                Serial.println("Closing!");
                Serial.println("");
                state = CLOSE;
            }

            break;

        // done, so close up the tcpClient
        case CLOSE:
            tcpClient.close();
            Serial.println("Closing TcpClient, Done with sketch.");
            state = DONE;
            break;

        case DONE:
        default:
            break;
    }

    // keep the stack alive each pass through the loop()
    DEIPcK::periodicTasks();
}

and here is the result on the serial monitor:

TCPEchoClient 3.0 Digilent, Copyright 2014 Got Connection Bytes Read Back: No bytes read back! ... No bytes read back! Closing! Closing TcpClient, Done with sketch.

Any ideas on how to sort out this? BTW I have my own webapp already with the php "hello world", how can I use the local DNS to retrieve the server's IP? Note: It has been a nightmare just to have some IDE working with this board. Right now I have MPIDE0150. Thanks in advance.


lstandage

Tue, 22 Aug 2017 17:53:52 +0000

MPIDE is definitely not the recommended IDE. You can switch to the Arduino IDE and install the chipKIT-core, which will give you everything you need.

You can also use MPLAB X, and our new plugin, chipKIT Sketch Importer, which will allow you to do debugging (as long as you have a debugger, like the chipKIT PGM).

I notice that you establish the connection with the server, but you don't send anything to the server. I think you have to send something to the server, via tcpClient.writeStream, before you will get anything back.


aabfm

Tue, 22 Aug 2017 20:07:00 +0000

Any suggestion on what to send to the server? Unfortunately the only, and closest, example I could find is the TCPEchoClient where it shows a command inside the WRITE state:

byte rgbWriteStream[] = {'*','W','r','o','t','e',' ','f','r','o','m',' ','t','c','p','C','l','i','e','n','t','.','w','r','i','t','e','S','t','r','e','a','m','*','\n'};
int cbWriteStream = sizeof(rgbWriteStream);
tcpClient.writeStream(rgbWriteStream, cbWriteStream);

Is it me or everyone is looking basically for webservers? Example after example there is only a few examples about clients, and, after a some days looking for it, I could only find a single example of a webclient that sends post parameters... :( but it doesn't work... (sorry for the steam...) Thx


majenko

Tue, 22 Aug 2017 20:22:14 +0000

You won't get anything back from a web server without sending it a request for a web page first.

For instance, for Google, send it:

GET / HTTP/1.1
Host: www.google.com
Connection close:
[extra blank line]

aabfm

Tue, 22 Aug 2017 20:33:43 +0000

I'll give it a try, thanks for your prompt answer. In the meantime, and sorry for my ignorance, if I were to send a couple of post parameters such as $_POST['name'] and $_POST['age'] to a script, for instance abcde.php and wanted to read the result from it such as the associated name stored in the database here are a couple of questions:

  • how would I send it?
  • what would be the best way to read it? xml result? json result? other?... Thx

majenko

Tue, 22 Aug 2017 20:42:50 +0000

The content would look like this:

POST /path/to/page.php HTTP/1.1
Host: www.mywebsite.com
Connection: close
Content-Length: 21
Content-Type: application/x-www-form-urlencoded

name=Bob+Smith&age=34

Note that the "Content-Length" must match what you put in the "body" (everything that follows the blank line).

The response can be in whatever form you find easiest to parse. The simpler the better.


majenko

Tue, 22 Aug 2017 20:43:53 +0000

Some reading for you: https://www.w3.org/Protocols/rfc2616/rfc2616.html


aabfm

Tue, 22 Aug 2017 20:56:35 +0000

Thanks a lot. I'll give a try first thing in the morning.


aabfm

Wed, 23 Aug 2017 16:19:25 +0000

GREAT NEWS!!!! IT IS ALIVE AND KICKING!!!! (sorry for the enthusiasm)

In order to avoid doing what I was complaining about here is the COMPLETE CODE to use the mx7ck board as a webclient. IDE: MPIDE0150 Board: CEREBOT MX7ck (DO NOT FORGET THE JUMPER ON JP11 AND USE USB UART PORT AND OF COURSE CHECK THE JUMPER JP3 FOR PSU SETTINGS) OS: Windows 7 64 (I'll give it a try later on with my Linux Mint machine)

And finally a big thanks to these friends: majenko and lstandage for guidance, ideas and examples.

Note: There are loads of "Serial.println"s and "Serial.print"s that were just for my debugging.

#include <IM8720PHY.h>
#include <DEIPcK.h>

IPv4 ip = {193,0,0,171};
IPv4 subnet = {255,255,255,0};
IPv4 gatew = {193,0,0,3};
const char * szIPServer = "216.58.206.100"; // Google
unsigned short portServer = 80; 

typedef enum
{
    NONE = 0,
    CONNECT,
    TCPCONNECT,
    WRITE,
    READ,
    CLOSE,
    DONE,
} STATE;

STATE state = CONNECT;
IPSTATUS    status;

unsigned tStart = 0;
unsigned tWait = 5000;

TCPSocket tcpClient;
byte rgbRead[1024];
int cbRead = 0;

void setup() {
    Serial.begin(38400);
    Serial.println("TCPEchoClient 3.0");
    Serial.println("Digilent, Copyright 2014");
    Serial.println("");
}

void loop()
{
    String message = "GET / HTTP/1.1\nHost: www.google.com\nConnection close:\n\n";
    byte rgbWriteStream[message.length()];
    message.getBytes(rgbWriteStream, message.length() + 1);
    int cbWriteStream = sizeof(rgbWriteStream);
    Serial.print("Data prepared to send:");
    Serial.println(cbWriteStream, DEC);
    
    if(boolean bi = state_machine(rgbWriteStream, cbWriteStream))
    {
      Serial.println("Posted");
    }
    else
    {
      Serial.println("NOT Posted");
    }
}
  
boolean state_machine(byte rgbWriteStream[], int cbWriteStream)
{

  byte rgbRead[1024];
  unsigned tStart = 0;
  unsigned tWait = 3000;
  int flag=0;
  for(;;)
  {
  int cbRead = 0;
  IPSTATUS status;
  switch(state)
    {

        case CONNECT:
            if(deIPcK.begin(ip,gatew,subnet))
            {
                Serial.println("Connected");
                state = TCPCONNECT;
            }
            else if(IsIPStatusAnError(status))
            {
                Serial.print("Unable to connection, status: ");
                Serial.println(status, DEC);
                state = CLOSE;
            }
            break;

        case TCPCONNECT:
            if(deIPcK.tcpConnect(szIPServer, portServer, tcpClient))
            {
                Serial.println("Connected to server.");
                Serial.print("Data to send:");
                Serial.println(cbWriteStream, DEC);
                state = WRITE;
            }
        break;

        case WRITE:
            if(tcpClient.isEstablished())
                {
                tcpClient.writeStream(rgbWriteStream, cbWriteStream);
                Serial.println("Bytes Read Back:");
                state = READ;
                tStart = (unsigned) millis();
                }
            break;

            case READ:

                if((cbRead = tcpClient.available()) > 0)
                {
                    Serial.println("TCP Available");
                    cbRead = cbRead < sizeof(rgbRead) ? cbRead : sizeof(rgbRead);
                    Serial.print("Size 1:");
                    Serial.println(cbRead, DEC);
                    cbRead = tcpClient.readStream(rgbRead, cbRead);

                    for(int i=0; i < cbRead; i++)
                    {
                        Serial.print((char)rgbRead[i]);
                    }
                    Serial.println(" -- END --");
                    Serial.print("Size 2:");
                    Serial.println(cbRead, DEC);
                }

                else if( (((unsigned) millis()) - tStart) > tWait )
                {
                    Serial.println("Next step: Closing");
                    state = CLOSE;
                }
                break;

        case CLOSE:
            tcpClient.close();
            Serial.println("Closing TcpClient!");
            state = DONE;
            break;

        case DONE:
            state = CONNECT;
            return cbRead;
        default:
            break;

    }
    DEIPcK::periodicTasks();
  }
}

Here is the result from the serial monitor:

TCPEchoClient 3.0 Digilent, Copyright 2014 Data prepared to send:55 Connected Connected to server. Data to send:55 Bytes Read Back: TCP Available Size 1:503 HTTP/1.1 302 Found Cache-Control: private Content-Type: text/html; charset=UTF-8 Referrer-Policy: no-referrer Location: http://www.google.co.uk/?gfe_rd=cr&ei=VKqdWabfDK7HXqGPlqAI Content-Length: 259 Date: Wed, 23 Aug 2017 16:16:20 GMT <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> <TITLE>302 Moved</TITLE></HEAD><BODY> <H1>302 Moved</H1> The document has moved <A HREF="http://www.google.co.uk/?gfe_rd=cr&ei=VKqdWabfDK7HXqGPlqAI">here</A>. </BODY></HTML> -- END -- Size 2:503 Next step: Closing Closing TcpClient! NOT Posted Data prepared to send:55

I still need to check why I'm having a "NOT Posted" message at end as it WAS really posted, but I'll have a look at it later. Cheers


aabfm

Wed, 23 Aug 2017 20:53:32 +0000

It also worked on my Linux Mint machine. I've also tried the UECIDE - much better! And easier to control! (I have used chipKit Pro MX7 board which apparently is the one succeeding the mx7ck)

I'm now trying to have the code checking the website every 5 seconds but no luck... Is there anything that should be done? the code is not too different from the one previously posted. Any ideas? Thx


aabfm

Thu, 24 Aug 2017 14:40:01 +0000

Hi everyone, Here is another update.

Back on my Windows machine, where I also installed UECIDE, I have now a running call (with intervals of 5 seconds) to the webserver. Enjoy the code (this time much tidier ;) ).

#include &lt;IM8720PHY.h&gt;
#include &lt;DEIPcK.h&gt;

int use_dhcp=0;
int debug01=1;
int debug02=0;
int phy_con=0;

IPv4 ip = {193,0,0,171};
IPv4 subnet = {255,255,255,0};
IPv4 gatew = {193,0,0,3};

const char * szIPServer = "216.58.206.100"; // Google
unsigned short portServer = 80; 

typedef enum
{
    NONE = 0,
    CONNECT,
    TCPCONNECT,
    WRITE,
    READ,
    CLOSE,
    DONE,
} STATE;

STATE state;
IPSTATUS status;

byte rgbRead[1024];
int cbRead = 0;

unsigned tStart = 0;
unsigned tWait = 3000;

TCPSocket tcpClient;

void setup()
{
		int con;
		  
		Serial.begin(38400);
    if (debug01)
    {
        Serial.println("WebClient 1.0 @ AM Copyright 2017");
        Serial.println("");
    }

    // Initialize PHY
		if (use_dhcp==1)
		{
		    // use DHCP
		    con=deIPcK.begin();
		}
		else
		{
		    // use fix IP
		    con=deIPcK.begin(ip,gatew,subnet);
		}

    if(con)
    {
        if (debug01) {Serial.println("PHY Connected");}
    }
    else if(IsIPStatusAnError(status))
    {
    		if (debug01)
    		{
        		Serial.print("Unable to connect, status: ");
        		Serial.println(status, DEC);
    		}
    }
}

void loop()
{
		String message = "GET / HTTP/1.1\nHost: www.google.com\nConnection close:\n\n";
    byte rgbWriteStream[message.length()];
    message.getBytes(rgbWriteStream, message.length() + 1);
    int cbWriteStream = sizeof(rgbWriteStream);
    int result;

		state = TCPCONNECT;
    result=call_server(rgbWriteStream, cbWriteStream);

    Serial.print("Size out:");
    Serial.println(result, DEC);
    Serial.println("Wait 5s...");
    Serial.print("");
    delay(5000);
}

int call_server(byte rgbWriteStream[], int cbWriteStream)
{
		int not_finished=1;
		int sent;
		
		while (not_finished)
		{
				switch(state)
	  		{
	  				case TCPCONNECT:
		            if(tcpClient.isEstablished())
		            {
				            state = WRITE;
		            }
		            else
		            {
		            		// connect to webserver szIPServer on port portServer and return result into tcpClient socket
				            if(deIPcK.tcpConnect(szIPServer, portServer, tcpClient))
				            {
				                state = WRITE;
				            }
		            }
	  						break;
	  				case WRITE:
	  						// send command to the server
		            if(tcpClient.isEstablished())
		            {
		                tcpClient.writeStream(rgbWriteStream, cbWriteStream);
		                state = READ;
		                tStart = (unsigned) millis();
		            }
	  						break;
	  				case READ:
	  						// receiving results from server
								if((cbRead = tcpClient.available()) &gt; 0)
		            {
		                cbRead = cbRead &lt; sizeof(rgbRead) ? cbRead : sizeof(rgbRead);
		                cbRead = tcpClient.readStream(rgbRead, cbRead);
		                // print results DEBUG ONLY
		                for(int i=0; i &lt; cbRead; i++)
		                {
		                    Serial.print((char)rgbRead[i]);
		                }
		                sent=cbRead;
		            }
		            else if( (((unsigned) millis()) - tStart) &gt; tWait )
		            {
		                state = CLOSE;
		            }
	  						break;
	  				case CLOSE:
	  						// closing socket
	  						tcpClient.close();
	  						state = DONE;
	  						break;
	  				case DONE:
	  						not_finished=0;
	  				default:
	  						break;
	  		}
	  		DEIPcK::periodicTasks();
		}
		return sent;
}

I am now proceeding to the post parameters. Until my next post (possibly on a new topic) enjoy this easy-to-understand (I think) piece of code. Thanks.


aabfm

Thu, 24 Aug 2017 21:22:35 +0000

Hi, Here comes the first question: how do I use a domain such as http://www.mydomain.com/script.php instead of the server IP address? I suppose that this is an item related to the DNS servers, but how do I configure them? and how/where do I use it? Thanks in advance.

PS: BTW, after the previous posts the mx7ck is now calling different websites (which respond in xml) to retrieve different information based on which button I am pressing (ex: BTN1 -> currency exchange, BTN2 -> local weather and BTN3 -> current unread items on my mailbox) and the info is being displayed on a 40x4 LCD, nice! ;) 8-)