diff --git a/README b/README.md similarity index 76% rename from README rename to README.md index dcfdafd..1267b49 100644 --- a/README +++ b/README.md @@ -1,11 +1,11 @@ -esp-httpd README +# esp-httpd README # This is the demonstration project for the small but powerful libesphttpd webserver for ESP8266(EX) chips. It is an example of how to make a module that can have the AP it connects to configured over a webbrowser. It also illustrates multiple flash layouts and some OTA update functionality. -ABOUT THE WEBSERVER +## ABOUT THE WEBSERVER ## The Good (aka: what's awesome) - Supports multiple connections, for eg simultaneous html/css/js/images downloading @@ -24,14 +24,14 @@ The Ugly (aka: bugs, misbehaviour) This can be theoretically remedied by either Espressif including an os_snprintf in their libs or by using some alternate printf lib, like elm-chans xprintf -SOURCE OF THIS CODE +## SOURCE OF THIS CODE ## The official esphttpd repo lives at http://git.spritesserver.nl/esphttpd.git/ and http://git.spritesserver.nl/libesphttpd.git/ . If you're a fan of Github, you can also peruse the official mirror at https://github.com/Spritetm/esphttpd and https://github.com/Spritetm/libesphttpd . If you want to discuss this code, there is a subforum at esp8266.com: http://www.esp8266.com/viewforum.php?f=34 . -ABOUT THE EXAMPLE +## ABOUT THE EXAMPLE ## When you flash the example into an ESP8266(EX) module, you get a small webserver with a few example pages. If you've already connected your module to your WLAN before, it'll keep those settings. When @@ -40,7 +40,7 @@ its STA+AP mode. Connect a computer to the newly formed access point and browse http://192.168.4.1/wifi in order to connect the module to your WiFi network. The example also allows you to control a LED that's connected to GPIO2. -BUILDING EVERYTHING +## BUILDING EVERYTHING ## For this, you need an environment that can compile ESP8266 firmware. Environments for this still are in flux at the moment, but I'm using esp-open-sdk: https://github.com/pfalcon/esp-open-sdk . @@ -48,11 +48,12 @@ You probably also need an UNIX-like system; I'm working on Debian Linux myself. To manage the paths to all this, you can source a small shell fragment into your current session. For example, I source a file with these contents: -export PATH=${PWD}/esp-open-sdk/xtensa-lx106-elf/bin:$PATH -export SDK_BASE=${PWD}/esp-open-sdk/sdk -export ESPTOOL=${PWD}/esptool/esptool.py -export ESPPORT=/dev/ttyUSB0 -export ESPBAUD=460800 + + export PATH=${PWD}/esp-open-sdk/xtensa-lx106-elf/bin:$PATH + export SDK_BASE=${PWD}/esp-open-sdk/sdk + export ESPTOOL=${PWD}/esptool/esptool.py + export ESPPORT=/dev/ttyUSB0 + export ESPBAUD=460800 Actual setup of the SDK and toolchain is out of the scope of this document, so I hope this helps you enough to set up your own if you haven't already. @@ -61,34 +62,31 @@ If you have that, you can clone out the source code: git clone http://git.spritesserver.nl/esphttpd.git/ This project makes use of heatshrink, which is a git submodule. To fetch the code: -cd esphttpd -git submodule init -git submodule update + + cd esphttpd + git submodule init + git submodule update Now, build the code: -make + + make Flash the code happens in 2 steps. First the code itself gets flashed. Reset the module into bootloader mode and enter 'make flash'. The 2nd step is to pack the static files the webserver will serve and flash that. Reset the module into -bootloader mode again and enter 'make htmlflash'. +bootloader mode again and enter `make htmlflash`. You should have a working webserver now. -WRITING CODE FOR THE WEBSERVER - -...errm... to be done. For now, look at the examples. Hey, you probably managed to find out how -the SDK works, this shouldn't be too hard :P +## WRITING CODE FOR THE WEBSERVER ## +See programming.md -CHANGE FROM SDK 0.9.3 (and earlier) TO SDK 0.9.4 (and later): -Change all occurences of -espconn_sent(connData->conn, (uint8 *)buff, len); -to -httpdSend(connData, buff, len) -please. The reason for this is that you can't do multiple espconn_sent calls serially anymore, so -httpd needs to buffer the writes now. This is only needed in your own code; the code that comes -with httpd already has this changed. +## CHANGE FROM SDK 0.9.3 (and earlier) TO SDK 0.9.4 (and later): ## +Change all occurences of `espconn_sent(connData->conn, (uint8 *)buff, len);` to +`httpdSend(connData, buff, len)` please. The reason for this is that you can't do multiple +espconn_sent calls serially anymore, so httpd needs to buffer the writes now. This is only +needed in your own code; the code that comes with httpd already has this changed. diff --git a/libesphttpd b/libesphttpd index fc41eb6..cdcfe51 160000 --- a/libesphttpd +++ b/libesphttpd @@ -1 +1 @@ -Subproject commit fc41eb64be45542943515d16cfaec73233c86e84 +Subproject commit cdcfe5167e0a6e8d59e1af5f3386275677293306 diff --git a/programming.md b/programming.md new file mode 100644 index 0000000..43a482c --- /dev/null +++ b/programming.md @@ -0,0 +1,112 @@ +# Intro to esphttpd developement # + +(Thanks to escardin, who wrote this.) + + +user_main.c and cgi.c provide good examples of setting up the webserver, processing input and output. + +## Setting up httpd ## +You need to define a list of urls and callbacks for those urls for processing input and transforming output. +At minimum, it must end with a NULL url. +The list is processed top to bottom, so it is best if wildcards are handled at the bottom. +Example: +HttpdBuiltInUrl builtInUrls[]={ + {"/", cgiRedirect, "/index.tpl"}, + {"/led.tpl", cgiEspFsTemplate, tplLed}, + {"/index.tpl", cgiEspFsTemplate, tplCounter}, + {"/led.cgi", cgiLed, NULL}, + {"*", cgiEspFsHook, NULL}, //Catch-all cgi function for the filesystem + {NULL, NULL, NULL} +}; + +The contents of each field is explained in URLs, CGI Callback and TPL Callback further down. + +If you plan on using serial logging, you need to include stdout.c & stdout.h and call stdoutInit() before starting the httpd. + +If you plan on serving up any templates or files, you need to call espFsInit. It is recommended to just place the following code unless you know what you're doing: + +// 0x40200000 is the base address for spi flash memory mapping, ESPFS_POS is the position +// where image is written in flash that is defined in Makefile. +#ifdef ESPFS_POS + espFsInit((void*)(0x40200000 + ESPFS_POS)); +#else + espFsInit((void*)(webpages_espfs_start)); +#endif + +You should now call any other initialization routines you may need. + +Now, call httpdInit() with the list of urls you created earlier and the port you wish httpd to listen on. + +## URLs ## +Urls are relative to the url root and must begin with a /, unless they are *. +A * is a wildcard and will match anything from the * onwards. +The * MUST be the last character in the url pattern to be a wildcard! +Examples: +'*' will match: '/', '/stuff', 'things', '/widgets.tpl' +'/stuff*' will match: '/stuff', '/stuff/', '/stuff/widgets.tpl', '/stuff.html' + +## CGI Callback ## +The specified cgi callback is called when the url it is tied to matches. +It is passed a pointer to the connection (HttpdConnData). +It returns one of HTTPD_CGI_MORE, HTTPD_CGI_DONE, HTTPD_CGI_NOTFOUND, HTTPD_CGI_AUTHENTICATED. If one of these is not returned, it will retry this url again (probably infinitely). +HTTPD_CGI_MORE means it has handled the request, but is not done sending data yet. +HTTPD_CGI_DONE means it has handled the request and is done sending data. +HTTPD_CGI_NOTFOUND and HTTPD_CGI_AUTHENTICATED means that it has not handled the request, and the url matching should continue with the next entry. + +## TPL Callback ## +The specified tpl callback is called for every token in the calling tpl file, as well as when the connection is aborted (token will be null). +It is passed a pointer to the connection data (HttpdConnData), a string token, and arguments. +If token is null, assume that the connection has died and it is time to clean up. +A token is the contents between two %. I.e. %ledstate% or %counter%. +It is the responisbility of the callback to write what should replace the token using httpdSend(); +The TPL Callback is only used (so far) if you set the CGI Callback to 'cgiEspFsTemplate'. +The return callback for TPL is not currently used, and should return one of HTTPD_CGI_MORE, HTTPD_CGI_DONE, HTTPD_CGI_NOTFOUND, HTTPD_CGI_AUTHENTICATED, though the use of each value is undefined at this time. + +## USEFUL BUILTIN FUNCTIONS ## + +base64_decode (base64.h): TODO describe how to use this + +captdnsInit (captdns.h): + - Creates a captive dns portal listening on the default ap network + +Serving files: + - espFsInit (espfs.h): Initializes access to the espfs block of flash. See above for basic usage, not recommended to mess around. + - espFsFlags (espfs.h): returns the flags for an opened file + - espFsRead (espfs.h): Read len bytes from file into buffer. Returns actual number of bytes read + - espFsClose (espfs.h): Close the file + - espFsOpen (espfs.h): open a file and return the file handle + +CGI Callbacks + - cgiEspFsHook (httpdespfs.h): attempts to read out the requested file as is (no template processing) + - cgiEspFsTemplate (httpdespfs.h): attempts to read out the requested file, with template processing (using the cgiArg tpl callback) + - cgiRedirect (httpd.h): Redirect to the url specified as a cgiArg (string) + - cgiRedirectToHostname (httpd.h): Redirect to the given http url, if it doesn't match the request url + - cgiRedirectApClientToHostname (httpd.h): Same as cgiRedirectToHostname, but only redirects if in the AP ip range + - authBasic (auth.h): performs http basic auth from the cgiArg callback function + - int cgiArg(HttpdConnData connData, int userIndex,char *userOut,int userOutLength, char *passOut,int passOutLength) + - return 1 if an entry at userIndex was found (with the username and password in userOut and passOut respectively) + - return 0 if no entry at userIndex was found (will cause authBasic to stop processing) + - OTA Firmware Updating + - cgiReadFlash (cgiflash.h): returns the first 512Kbyte of firmware + - cgiGetFirmwareNext (cgiflash.h): Returns which firmware should be uploaded next + - cgiUploadFirmware (cgiflash.h): replace firmware with POSTed firmware, after some basic validation + - cgiRebootFirmware (cgiflash.h): reboot after firmware finishes uploading? + - OTA Wifi Setup + - cgiWiFiScan (cgiwifi.h): Initiate a scan for wifi access points, and return the status/result as JSON + - tplWlan (cgiwifi.h): Template processor for the httpd demo template page + - cgiWiFi (cgiwifi.h): not implemented? + - cgiWiFiConnect (cgiwifi.h): Connect to the specified essid using the passwd provided + - cgiWiFiSetMode (cgiwifi.h): Set the esp8266 wifi mode (AP, Station, AP+Station) and reboot + - cgiWiFiConnStatus (cgiwifi.h): Return the station connection status as JSON + +Working with HTTP + - httpdRedirect (httpd.h): issue a 302 redirect to the given url + - httpdUrlDecode (httpd.h): decodes a percent encoded url + - httpdFindArg (httpd.h): finds the specified argument in the get or post data, and returns the percent decoded version of it + - httpdInit (httpd.h): Starts an http server on the given port for the given urls + - httpdGetMimetype (httpd.h): returns the mimetype based on the url extension + - httpdStartResponse (httpd.h): start http response (must be called first, and only once) + - httpdHeader (httpd.h): sends a particular http response header + - httpdEndHeaders (httpd.h): completes sending headers (no more headers may be sent) + - httpdGetHeader (httpd.h): retrieves a specific request header + - httpdSend (httpd.h): add data to be sent to the user, returns 1 for success, 0 for out of memory