Seattle, WA USA
Online
Brattain Member
Karma: 314
Posts: 35510
Seattle, WA USA
|
 |
« Reply #15 on: November 23, 2012, 06:46:02 pm » |
^^This should be fine, right? It's OK. It's far more complicated than it needs to be. int pos = strlen(readString); if(pos < 30) { readString[pos++] = c; readString[pos] = '\0'; } Does the same thing, in less code. I changed this:...to this:...It is supposed to set PIN to the index of where "PIN" is in the readString There are several problems with the changed code. First the character 'PIN' will never appear in readString. The string "PIN" might. The output of strrchr() is a pointer to where the last occurrence of a character is in a string. That pointer could be subtracted from a pointer to the first character of the string, to get the relative position. It should not be used in the way you are trying to use it. The strrchr() function is not the correct function to be using to locate a string in a string. The strstr() function is. Frankly, it's hard to help you with general parsing questions. Seeing the string(s) you want to parse, and helping parse those specific strings would be far easier. You might want to look at the strtok function.
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 218
Posts: 13897
Lua rocks!
|
 |
« Reply #16 on: November 23, 2012, 06:52:58 pm » |
static char readString[30]; ... int pos = strlen(readString); if(pos < 30) { readString[pos++] = c; readString[pos] = '\0'; } Better check for < 29 in that case. The null takes a position, so you have room for 29 characters.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 27
|
 |
« Reply #17 on: November 23, 2012, 08:50:54 pm » |
Frankly, it's hard to help you with general parsing questions. Seeing the string(s) you want to parse, and helping parse those specific strings would be far easier.
I based my program off the example Arduino server code, and to be honest I'm actually still confused on that part. Here is my program(still a little messy and unfinished): #include <SPI.h> #include <Ethernet.h> #include <LiquidCrystal.h> #include <Time.h> #include <TimeAlarms.h>
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x98, 0x26 }; IPAddress ip(192,168,1,134); // Initialize the Ethernet server library // with the IP address and port you want to use // (port 80 is default for HTTP): EthernetServer server(80);
int pin[8] = {2,3,4,5,6,7,8,9}; static char readString[30]; static char *state[8] = {"OFF","OFF","OFF","OFF","OFF","OFF","OFF","OFF",}; static char *pinOn[8] = {"PIN2=T","PIN3=T","PIN4=T","PIN5=T","PIN6=T","PIN7=T","PIN8=T","PIN9=T"}; static char *pinOff[8] = {"PIN2=F","PIN3=F","PIN4=F","PIN5=F","PIN6=F","PIN7=F","PIN8=F","PIN9=F"}; /* LCD */ LiquidCrystal lcd(14,15,16,17,18,19); int backLight = 1; void setup() { // start the Ethernet connection and the server: Ethernet.begin(mac, ip); server.begin(); //Time setup setTime(7,30,0,11,22,12); //LCD setup pinMode(backLight, OUTPUT); digitalWrite(backLight, HIGH); lcd.begin(20, 4); lcd.clear(); lcd.setCursor(0,0); lcd.print(F("SprinkDuino")); delay(5000); lcd.clear(); //Sets relay pins (2-9) as output for(int i = 2; i < 10; i++){ pinMode(i, OUTPUT); } for(int i = 2; i < 10; i++){ digitalWrite(i, HIGH); //HIGH is off } }
void loop() { digitalClockDisplay(); Alarm.delay(1000); EthernetClient client = server.available(); // listen for incoming clients if (client) { boolean currentLineIsBlank = true; // an http request ends with a blank line while (client.connected()) { if (client.available()) { char c = client.read(); int pos = strlen(readString); if(pos < 29) { readString[pos++] = c; readString[pos] = '\0'; } if (c == '\n' && currentLineIsBlank) { for(int i = 0; i < 8; i++){ if (strstr(readString, "PIN") == pinOn[i]) { //Turns current pin on digitalWrite(pin[i], LOW); state[i] = "ON"; } else if (strstr(readString, "PIN") == pinOff[i]) { //Turns current pin off digitalWrite(pin[i], HIGH); state[i] = "OFF"; } } if(strstr(readString, "PIN") == "PINA=F") { //Turns all pins off for(int i = 0; i < 8; i++){ digitalWrite(pin[i], HIGH); state[i] = "OFF"; } } else if(strstr(readString, "PIN") == "PINA=T") { //Turns all pins on for(int i = 0; i < 8; i++){ digitalWrite(pin[i], LOW); state[i] = "ON"; } } } client.println(F("HTTP/1.1 200 OK")); client.println(F("Content-Type: text/html")); client.println(); client.println(F("<title>SprinkDuino</title>")); client.println(F("<h1 color=red style=text-align:center;>Welcome to SprinkDuino!</h1>")); client.print(F("<table border=0><tr>")); client.println(F("<td><a href=\"./?PINA=T\"><button><font size=4>TURN ALL <font color=green>ON</font></font></button><a></td>")); client.println(F("<td><a href=\"./?PINA=F\"><button><font size=4>TURN ALL <font color=red>OFF</font></font></button><a></td>")); client.println(F("<tr>")); for(int i = 2; i < 10; i++){ //Prints state of sprinkler pin client.print(F("<td>")); client.print(F("<font size=4>Sprinkler ")); client.print(i-1); client.print(F(" is ")); if(state[i-2] == "ON"){ client.print(F("<b><font color=green>")); client.print(state[i-2]); client.print(F("</font></b></font>")); client.print(F("</td>")); } else { client.print(F("<b><font color=red>")); client.print(state[i-2]); client.print(F("</font></b></font>")); client.print(F("</td>")); } if (state[i-2] == "ON") { //Turns sprinkler pin on or off client.print(F("<td>")); client.print(F("<a href=\"./?")); client.print(pinOff[i-2]); client.print(F("\"><button>Turn Off</button><a>")); client.print(F("</td>")); client.print(F("<tr>")); } else { client.print(F("<td>")); client.print(F("<a href=\"./?")); client.print(pinOn[i-2]); client.print(F("\"><button>Turn On</button><a>")); client.print(F("</td>")); client.print(F("<tr>")); } client.print(F("</table>")); break; } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); readString[0] = '\0'; // close the connection: client.stop(); } }
void digitalClockDisplay() { lcd.clear(); lcd.setCursor(0,0); lcd.print(F("Time")); lcd.setCursor(0,1); lcd.print(hour()); printDigits(minute()); printDigits(second()); }
void printDigits(int digits) { lcd.print(F(":")); if(digits < 10) lcd.print('0'); lcd.print(digits); }
So if you want pin 2 to turn on, you would click the button which appends "PIN2=T" onto the end of the URL. readString is then set to PIN2=T and compared to pinOn[0]. If it is true pin 2 is set to LOW, turning the relay on. I just don't fully get what 'c' is doing...I'm guessing since it is expected to be the new line character '\n', once you press the button the program will interpret the URL and set the readString accordingly? Sorry to be jumping around to different topics, but the program is now crashing similar to how it was previously. When I open up the page, it repeats the following over and over (with a few buttons that I couldn't paste here): Welcome to SprinkDuino! Sprinkler 1 is OFF HTTP/1.1 200 OK Content-Type: text/html
Since I'm not using strings anymore, I'm guessing it's some kind of memory leak? Could it also be because I'm trying to do too much formatting with the HTML?
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 218
Posts: 13897
Lua rocks!
|
 |
« Reply #18 on: November 23, 2012, 08:59:54 pm » |
if (strstr(readString, "PIN") == pinOn[i]) { //Turns current pin on
This is comparing addresses, not what they point to. More like: if (strcmp (strstr(readString, "PIN"), pinOn[i]) == 0) { //Turns current pin on
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Online
Brattain Member
Karma: 314
Posts: 35510
Seattle, WA USA
|
 |
« Reply #19 on: November 23, 2012, 09:16:09 pm » |
You could simplify your parsing quite a bit. Make the name a number, like "2", not a value like "PIN2" Make the value a string like "T;" or "F;", instead of "T" or "F".
Then, the URL will contain something like "?2=T;". You can store the whole server response in the char array.
Then, use strtok(), with ? as the delimiter. Throw that value away. Call strtok() again with NULL as the string to parse and "=" as the delimiter. The token will be "2". That's easy to turn into a number. Do so. Use that number as the array index
Then, call strtok() again with NULL and ";". The token will be "T" or "F". Use that to decide what to do with the known pin number.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 27
|
 |
« Reply #20 on: November 23, 2012, 10:30:18 pm » |
Thanks for all the suggestions! I changed the code to using the token method and this is what I came up with: #include <SPI.h> #include <Ethernet.h> #include <LiquidCrystal.h> #include <Time.h> #include <TimeAlarms.h>
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x98, 0x26 }; IPAddress ip(192,168,1,134); EthernetServer server(80);
int pin[8] = {2,3,4,5,6,7,8,9}; static char readString[30] = {'\0'}; static char *state[8] = {"OFF","OFF","OFF","OFF","OFF","OFF","OFF","OFF",}; static char *on = "T;"; static char *off = "F;";
/* LCD */ LiquidCrystal lcd(14,15,16,17,18,19); int backLight = 1; void setup() { // start the Ethernet connection and the server: Ethernet.begin(mac, ip); server.begin(); //Time setup setTime(7,30,0,11,22,12); //LCD setup pinMode(backLight, OUTPUT); digitalWrite(backLight, HIGH); lcd.begin(20, 4); lcd.clear(); lcd.setCursor(0,0); lcd.print(F("SprinkDuino")); delay(5000); lcd.clear(); //Sets relay pins (2-9) as output for(int i = 2; i < 10; i++){ pinMode(i, OUTPUT); } for(int i = 2; i < 10; i++){ digitalWrite(i, HIGH); //HIGH is off } }
void loop() { digitalClockDisplay(); Alarm.delay(1000); EthernetClient client = server.available(); // listen for incoming clients if (client) { boolean currentLineIsBlank = true; // an http request ends with a blank line while (client.connected()) { if (client.available()) { char c = client.read(); int pos = strlen(readString); if(pos < 29) { pos++; readString[pos] = c; } char* response = strtok(readString, "?"); response = strtok(NULL, "="); int val = atoi(response); response = strtok(NULL, ";"); char trueFalse; if(response == "T"){ trueFalse = 'T'; } else { trueFalse = 'F'; }
if (c == '\n' && currentLineIsBlank) { for(int i = 0; i < 8; i++){ if ((val == pin[i]) && (trueFalse == 'T')) { //Turns current pin on digitalWrite(pin[i], LOW); state[i] = "ON"; } else if ((val == pin[i]) && (trueFalse == 'F')) { //Turns current pin off digitalWrite(pin[i], HIGH); state[i] = "OFF"; } } if((val == 10) && (trueFalse == 'T')) { //Turns all pins off for(int i = 0; i < 8; i++){ digitalWrite(pin[i], HIGH); state[i] = "OFF"; } } else if((val == 10) && (trueFalse == 'F')) { //Turns all pins on for(int i = 0; i < 8; i++){ digitalWrite(pin[i], LOW); state[i] = "ON"; } } } client.println(F("HTTP/1.1 200 OK")); client.println(F("Content-Type: text/html")); client.println(); client.println(F("<title>SprinkDuino</title>")); client.println(F("<h1 color=red style=text-align:center;>Welcome to SprinkDuino!</h1>")); client.print(F("<table border=0><tr>")); client.println(F("<td><a href=\"./?10=T;\"><button><font size=4>TURN ALL <font color=green>ON</font></font></button><a></td>")); client.println(F("<td><a href=\"./?10=F;\"><button><font size=4>TURN ALL <font color=red>OFF</font></font></button><a></td>")); client.println(F("<tr>")); for(int i = 0; i < 8; i++){ //Prints state of sprinkler pin client.print(F("<td>")); client.print(F("<font size=4>Sprinkler ")); client.print(i+1); client.print(F(" is ")); if(strcmp (state[i], "ON") == 0){ client.print(F("<b><font color=green>")); client.print(state[i]); client.print(F("</font></b></font>")); client.print(F("</td>")); } else { client.print(F("<b><font color=red>")); client.print(state[i]); client.print(F("</font></b></font>")); client.print(F("</td>")); } if (strcmp (state[i], "ON") == 0){ //Turns sprinkler pin on or off client.print(F("<td>")); client.print(F("<a href=\"./?")); client.print(pin[i]); client.print("="); client.print(off); client.print(F("\"><button>Turn Off</button><a>")); client.print(F("</td>")); client.print(F("<tr>")); } else { client.print(F("<td>")); client.print(F("<a href=\"./?")); client.print(pin[i]); client.print("="); client.print(on); client.print(F("\"><button>Turn On</button><a>")); client.print(F("</td>")); client.print(F("<tr>")); } client.print(F("</table>")); break; } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); readString[0] = '\0'; // close the connection: client.stop(); } }
void digitalClockDisplay() { lcd.clear(); lcd.setCursor(0,0); lcd.print(F("Time")); lcd.setCursor(0,1); lcd.print(hour()); printDigits(minute()); printDigits(second()); }
void printDigits(int digits) { lcd.print(F(":")); if(digits < 10) lcd.print('0'); lcd.print(digits); }
EDIT: I changed the code a bit since this post and updated it ^^ However, it's still crashing like before so I can't tell if it's working...any idea what that could be?
|
|
|
|
« Last Edit: November 23, 2012, 11:32:35 pm by ryanmcclure4 »
|
Logged
|
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 218
Posts: 13897
Lua rocks!
|
 |
« Reply #21 on: November 23, 2012, 11:23:23 pm » |
if(state[i] == "ON"){
You are still comparing pointers and not the contents.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 27
|
 |
« Reply #22 on: November 23, 2012, 11:31:04 pm » |
Thanks for catching that, I changed it to if (strcmp (state[i], "ON") == 0)
Still crashing though 
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 218
Posts: 13897
Lua rocks!
|
 |
« Reply #23 on: November 23, 2012, 11:39:27 pm » |
I'm concerned about the order you are doing things here: while (client.connected()) { if (client.available()) {
char c = client.read();
char* response = strtok(readString, "?"); response = strtok(NULL, "=");
Potentially you have read a single byte, but you are doing strtok twice and other stuff. I advise you to collect an entire line, then start breaking it up. A lot of the concepts are the same as described here: http://www.gammon.com.au/serial
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 27
|
 |
« Reply #24 on: November 23, 2012, 11:51:07 pm » |
I must've accidentally deleted that when I changed to the token method. Would this be the correct way to do that? #include <SPI.h> #include <Ethernet.h> #include <LiquidCrystal.h> #include <Time.h> #include <TimeAlarms.h>
byte mac[6] = { 0x90, 0xA2, 0xDA, 0x0D, 0x98, 0x26 }; IPAddress ip(192,168,1,134); EthernetServer server(80);
int pin[8] = {2,3,4,5,6,7,8,9}; static char readString[30] = {'\0'}; static char *state[8] = {"OFF","OFF","OFF","OFF","OFF","OFF","OFF","OFF",}; static char *on = "T;"; static char *off = "F;";
/* LCD */ LiquidCrystal lcd(14,15,16,17,18,19); int backLight = 1; void setup() { // start the Ethernet connection and the server: Ethernet.begin(mac, ip); server.begin(); //Time setup setTime(7,30,0,11,22,12); //LCD setup pinMode(backLight, OUTPUT); digitalWrite(backLight, HIGH); lcd.begin(20, 4); lcd.clear(); lcd.setCursor(0,0); lcd.print(F("SprinkDuino")); delay(5000); lcd.clear(); //Sets relay pins (2-9) as output for(int i = 2; i < 10; i++){ pinMode(i, OUTPUT); } for(int i = 2; i < 10; i++){ digitalWrite(i, HIGH); //HIGH is off } }
void loop() { digitalClockDisplay(); Alarm.delay(1000); EthernetClient client = server.available(); // listen for incoming clients if (client) { boolean currentLineIsBlank = true; // an http request ends with a blank line while (client.connected()) { if (client.available()) { char c = client.read(); int pos = strlen(readString); if(pos < 29) { readString[pos++] = c; readString[pos] = '\0'; } char* response = strtok(readString, "?"); response = strtok(NULL, "="); int val = atoi(response); response = strtok(NULL, ";"); char trueFalse; if(response == "T"){ trueFalse = 'T'; } else { trueFalse = 'F'; }
if (c == '\n' && currentLineIsBlank) { for(int i = 0; i < 8; i++){ if ((val == pin[i]) && (trueFalse == 'T')) { //Turns current pin on digitalWrite(pin[i], LOW); state[i] = "ON"; } else if ((val == pin[i]) && (trueFalse == 'F')) { //Turns current pin off digitalWrite(pin[i], HIGH); state[i] = "OFF"; } } if((val == 10) && (trueFalse == 'T')) { //Turns all pins off for(int i = 0; i < 8; i++){ digitalWrite(pin[i], HIGH); state[i] = "OFF"; } } else if((val == 10) && (trueFalse == 'F')) { //Turns all pins on for(int i = 0; i < 8; i++){ digitalWrite(pin[i], LOW); state[i] = "ON"; } } } client.println(F("HTTP/1.1 200 OK")); client.println(F("Content-Type: text/html")); client.println(); client.println(F("<title>SprinkDuino</title>")); client.println(F("<h1 color=red style=text-align:center;>Welcome to SprinkDuino!</h1>")); client.print(F("<table border=0><tr>")); client.println(F("<td><a href=\"./?10=T;\"><button><font size=4>TURN ALL <font color=green>ON</font></font></button><a></td>")); client.println(F("<td><a href=\"./?10=F;\"><button><font size=4>TURN ALL <font color=red>OFF</font></font></button><a></td>")); client.println(F("<tr>")); for(int i = 0; i < 8; i++){ //Prints state of sprinkler pin client.print(F("<td>")); client.print(F("<font size=4>Sprinkler ")); client.print(i+1); client.print(F(" is ")); if(strcmp (state[i], "ON") == 0){ client.print(F("<b><font color=green>")); client.print(state[i]); client.print(F("</font></b></font>")); client.print(F("</td>")); } else { client.print(F("<b><font color=red>")); client.print(state[i]); client.print(F("</font></b></font>")); client.print(F("</td>")); } if (strcmp (state[i], "ON") == 0){ //Turns sprinkler pin on or off client.print(F("<td>")); client.print(F("<a href=\"./?")); client.print(pin[i]); client.print("="); client.print(off); client.print(F("\"><button>Turn Off</button><a>")); client.print(F("</td>")); client.print(F("<tr>")); } else { client.print(F("<td>")); client.print(F("<a href=\"./?")); client.print(pin[i]); client.print("="); client.print(on); client.print(F("\"><button>Turn On</button><a>")); client.print(F("</td>")); client.print(F("<tr>")); } client.print(F("</table>")); break; } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); readString[0] = '\0'; // close the connection: client.stop(); } }
void digitalClockDisplay() { lcd.clear(); lcd.setCursor(0,0); lcd.print(F("Time")); lcd.setCursor(0,1); lcd.print(hour()); printDigits(minute()); printDigits(second()); }
void printDigits(int digits) { lcd.print(F(":")); if(digits < 10) lcd.print('0'); lcd.print(digits); }
Thanks for the link, input makes a lot more sense now.
|
|
|
|
« Last Edit: November 23, 2012, 11:56:37 pm by ryanmcclure4 »
|
Logged
|
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 218
Posts: 13897
Lua rocks!
|
 |
« Reply #25 on: November 23, 2012, 11:55:02 pm » |
Would this be the correct way to do that? Not really. Wait until the entire line arrives, then parse it. That is, wait until the newline, like in the link. Bear in mind strtok changes the string it is parsing. I don't particularly like it, because of that. Changing it multiple times (each time you loop) is almost certainly going to lead to incorrect results.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 50
Posts: 6549
Arduino rocks
|
 |
« Reply #26 on: November 24, 2012, 12:03:24 am » |
Out of nowhere, when I was testing the program, I clicked on the "turn all on" button and it turns all the relays on (like its supposed to do) but right after that it redirects me to a page of HTML code. Maybe you should go back to a basic web server setup and get it working again. Too much unneeded churn to diagnose and correct the problem. Apparently it wasn't a String class issue.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 27
|
 |
« Reply #27 on: November 24, 2012, 12:07:47 am » |
Not really. Wait until the entire line arrives, then parse it. That is, wait until the newline, like in the link.
So this would be more appropriate?: ... ... if (strcmp (state[i], "ON") == 0){ //Turns sprinkler pin on or off client.print(F("<td>")); client.print(F("<a href=\"./?")); client.print(pin[i]); client.print("="); client.print(off); client.print(F("\"><button>Turn Off</button><a>")); client.print(F("</td>")); client.print(F("<tr>")); char* response = strtok(readString, "?"); response = strtok(NULL, "="); val = atoi(response); response = strtok(NULL, ";"); if(response == "T"){ trueFalse = 'T'; } else { trueFalse = 'F'; } } ... ...
Maybe you should go back to a basic web server setup and get it working again. Too much unneeded churn to diagnose and correct the problem. Apparently it wasn't a String class issue.
I think I'll do that. I'm going insane trying to get this to work haha. Thanks again for all the help everyone
|
|
|
|
|
Logged
|
|
|
|
|
|