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!