UK
Offline
Newbie
Karma: 0
Posts: 18
Arduino rocks
|
 |
« on: January 19, 2012, 09:15:09 am » |
I'm using the ethercard library ( https://github.com/jcw/ethercard) to set the Arduino up as a web client so I can read data from a website. All this is working correctly and the demo webClient sketch ( https://github.com/jcw/ethercard/blob/master/examples/webClient/webClient.ino) works perfectly. I have even change the web site and page to be access and the correct output is sent to the serial monitor. My problem is that my knowledge of C and pointers is very limited. I know that Ethernet::buffer is an array of bytes using pointers. What I am trying to do is read the Google XML weather data from http://www.google.com//ig/api?weather=LondonExtract the current temp_c, humidity, icon and wind_condition data and use them to create an output. Where I am failing is how to parsing a char. Any advice or pointers (sorry for pun) on how to do this would be appreciated. Below is the webclient code I am working from // Demo using DHCP and DNS to perform a web client request. // 2011-06-08 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
#include <EtherCard.h>
// ethernet interface mac address, must be unique on the LAN static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700]; static uint32_t timer;
char website[] PROGMEM = "www.google.com";
// called when the client request is complete static void my_callback (byte status, word off, word len) { Serial.println(">>>"); Ethernet::buffer[off+300] = 0; Serial.print((const char*) Ethernet::buffer + off); Serial.println("..."); }
void setup () { Serial.begin(57600); Serial.println("\n[webClient]");
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) Serial.println( "Failed to access Ethernet controller"); if (!ether.dhcpSetup()) Serial.println("DHCP failed");
ether.printIp("IP: ", ether.myip); ether.printIp("GW: ", ether.gwip); ether.printIp("DNS: ", ether.dnsip);
if (!ether.dnsLookup(website)) Serial.println("DNS failed"); ether.printIp("SRV: ", ether.hisip); }
void loop () { ether.packetLoop(ether.packetReceive()); if (millis() > timer) { timer = millis() + 5000; Serial.println(); Serial.print("<<< REQ "); ether.browseUrl(PSTR("/foo/"), "bar", website, my_callback); } }
|
|
|
|
|
Logged
|
|
|
|
|
United Kingdom
Offline
Faraday Member
Karma: 131
Posts: 4690
|
 |
« Reply #1 on: January 19, 2012, 10:27:31 am » |
Please use the # button when posting code, it makes it easier to read. I found a library for parsing XML on arduino at http://john.crouchley.com/blog/archives/454. Alternatively, you can search for strings and characters inside a null terminated string using the strstr and strchr functions from the standard C library.
|
|
|
|
|
Logged
|
Formal verification of safety-critical software, software development, and electronic design and prototyping. http://www.eschertech.com
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 1
|
 |
« Reply #2 on: January 19, 2012, 11:17:22 am » |
Have you got a sample of the output ?
|
|
|
|
|
Logged
|
|
|
|
|
India
Offline
Jr. Member
Karma: 0
Posts: 58
OS Developer, ASIC and FPGA designer
|
 |
« Reply #3 on: January 19, 2012, 12:17:40 pm » |
I generally use strstr() function: char buffer[]="+CBC: 0,99,4190" ; // this is a return string by GSM modem 0,charge level, millivolt char *ptr; //temp pointer variable for pointer artihmetic char *fieldPtr; //temp pointer variable for pointer artihmetic : : : : ptr=strstr(buffer,"+CBC:"); // if substring found in buffer it return address ofstart character of matched string // if not matched it returned NULL if(ptr!=NULL) { ptr=strstr(ptr,","); Serial.println(ptr); // will print :",99,4190" // you can use pointer arithmetic to get the field while(ptr!=NULL) { ptr++; fieldPtr=ptr; ptr=strstr(ptr,","); *ptr='\0'; Serial.println(fieldPtr); } } --------Output--------------------------------- ,99,4190 99 4190
|
|
|
|
|
Logged
|
|
|
|
|
UK
Offline
Newbie
Karma: 0
Posts: 18
Arduino rocks
|
 |
« Reply #4 on: January 20, 2012, 06:34:42 am » |
I generally use strstr() function: char buffer[]="+CBC: 0,99,4190" ; // this is a return string by GSM modem 0,charge level, millivolt char *ptr; //temp pointer variable for pointer artihmetic char *fieldPtr; //temp pointer variable for pointer artihmetic : : : : ptr=strstr(buffer,"+CBC:"); // if substring found in buffer it return address ofstart character of matched string // if not matched it returned NULL if(ptr!=NULL) { ptr=strstr(ptr,","); Serial.println(ptr); // will print :",99,4190" // you can use pointer arithmetic to get the field while(ptr!=NULL) { ptr++; fieldPtr=ptr; ptr=strstr(ptr,","); *ptr='\0'; Serial.println(fieldPtr); } } --------Output--------------------------------- ,99,4190 99 4190
pravas - Thanks. This looks like the kind of thing I'm trying to do but for a web page rather than GPS. I think some experimenting over the weekend will see if I understand what you are saying. Albert.
|
|
|
|
|
Logged
|
|
|
|
|
India
Offline
Jr. Member
Karma: 0
Posts: 58
OS Developer, ASIC and FPGA designer
|
 |
« Reply #5 on: January 20, 2012, 06:55:52 am » |
Yes you can use the webpage XML data into the buffer.
char buffer[]="------------------------------XML DATA-----------------------------------------"; //This is a character array buffer.
In logic you must Identify the token, FieldName, FieldValue etc.
Goodluck for your experiment..
|
|
|
|
|
Logged
|
|
|
|
|
Ontario
Offline
God Member
Karma: 15
Posts: 717
|
 |
« Reply #6 on: January 20, 2012, 02:06:53 pm » |
The data returned from " http://www.google.com//ig/api?weather=London" is 1371 bytes, not counting headers. It us unlikely you will be 100% successful with the approach of loading the whole response into a string and searching around in it with stsrstr(). I would structure this as a parser like below that uses a small buffer to recognize just one tag at a time, and then feed all the data you receive into it. This allows you to avoid saving huge swaths of the response at once. You just feed your data into handle_input() one character at a time and it does the rest. char token[TOKEN_LEN]; uint8_t input_len = 0;
void handle_input(uint8_t c) { int temp;
/* c = '<', then a new tag sequence is starting */ if (c == '<') { input_len = 0; return; }
/* c = '>', a tag sequence is complete. * Check if this is a specific tag */ if (c == '>') { token[input_len] = 0;
if (strncmp(token, "temp_c data=\"", 13) != 0) return;
temp = atoi(token + 13);
// Now what? // Serial.print("got temperature "); Serial.print(temp);
}
/* otherwise we have an input character */ if (input_len <= TOKEN_LEN - 1) token[input_len++] = c; }
|
|
|
|
|
Logged
|
|
|
|
|
UK
Offline
Newbie
Karma: 0
Posts: 18
Arduino rocks
|
 |
« Reply #7 on: January 29, 2012, 04:24:27 pm » |
Thank you for the advice. I have a feeling for me I'm byting off more than I can chew for now. I think I need to learn a bit more C++ before I can get my head around this.
Again, thanks for the advice. Albert.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 3
|
 |
« Reply #8 on: February 08, 2012, 06:08:52 pm » |
Hey, I have same problem with reading the array – have you found a solution ? I can call a web page, and in my serial monitor can I read that I receive the correct data from the web server, but how can “work” with my received data ? /Per
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 316
Posts: 35590
Seattle, WA USA
|
 |
« Reply #9 on: February 08, 2012, 07:50:14 pm » |
but how can “work” with my received data ? Collecting the data in an array is the first step. Then, define what ""work" with my received data" means. There are plenty of examples around of parsing the data that a client sends to the Arduino server, or that an Arduino client fetches from a server.
|
|
|
|
|
Logged
|
|
|
|
|
|