AF_XPort and lighttpd

Recently I was building a project for a client, who needed an internet-controlled display device. For quick development time and minimal budget, I selected an Arduino Duemilanove, XPort Shield, and XPort Direct from Lady Ada's Adafruit store. Soldered everything together, tested and configured the XPort, everything worked. Then I wrote the necessary code to request data from a web server, that all worked too.

Finally I took the project down to the client's office in Mountain View and set it up...didn't work. I ended up working on the project for about four hours trying to get it running (minus some tricky subnet issues...use increments of 8 bits on an XPort). The client was using lighttpd to serve the display data, and I had been using Apache for testing. HTTP is HTTP, right? It should work on either? It didn't. I set up an Apache server on my laptop and everything worked great...point the Arduino sketch back at the client server, nothing worked. I kept getting "501 - Not Implemented" errors from the web server. If I opened up a telnet session directly to the web server and manually typed in the request the Arduino was sending, it worked.

Finally, I took the project back home and set up my own lighttpd server. Since I controlled the server, I could easily tail logs and see requests as they came in. Interesting; my Apache logs showed a valid request, but my lighttpd logs showed a line break right at the beginning of a valid request! I opened up the AF_XPort library and found this:

uint8_t AF_XPort::connect(char *ipaddr, long port) {
  char ret;
 
  xportserial.print('C');
  xportserial.print(ipaddr);
  xportserial.print('/');
  xportserial.println(port);
  // wait for 'C'
  if (serialavail_timeout(3000)) { // 3 second timeout
    ret = xportserial.read();
    //Serial.print("Read: "); Serial.print(d, HEX);
    if (ret != 'C') {
      return ERROR_BADRESP;
    }
  } else {
    return ERROR_TIMEDOUT;
  }
  return 0;
}

That code is supposed to generate the command that tells the XPort to connect to a specific IP address and port. However, note the "xportserial.println(port);" command. Println will put a carriage return and linefeed after the printed text, but the XPort user manual says this:

Quote:
Attempts to connect when directed by a command string received from the serial port. The first character of the command string must be a C (ASCII 0x43), and the last character must be either a carriage return (ASCII 0x0D) or a line feed (0x0A).
That means a linefeed was always going out ahead of the actual GET request. Apache appears to ignore this, while lighttpd throws a 501 error. I modified the code as below:
uint8_t AF_XPort::connect(char *ipaddr, long port) {
  char ret;
 
  xportserial.print('C');
  xportserial.print(ipaddr);
  xportserial.print('/');
  xportserial.print(port);
  xportserial.print('\r');
  // wait for 'C'
  if (serialavail_timeout(3000)) { // 3 second timeout
    ret = xportserial.read();
    //Serial.print("Read: "); Serial.print(d, HEX);
    if (ret != 'C') {
      return ERROR_BADRESP;
    }
  } else {
    return ERROR_TIMEDOUT;
  }
  return 0;
}
This code works perfectly with lighttpd. I've uploaded a new version of the library, which is also modified to use NewSoftSerial instead of AF_SoftSerial: http://www.macetech.com/AF_XPort_for_NewSoftSerial.zip


Submitted by Garrett on Tue, 03/17/2009 - 17:19.

good bug catch!! keep up

good bug catch!!
keep up the good work!

Post new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
Please prove you are sentient by typing the correct phrase below (capital letters only):
vocabula_y: