Moved out each demos' functionality library files (e.g. Ring Buffer library) to ...
[pub/lufa.git] / Demos / Device / RNDISEthernet / Lib / Webserver.c
diff --git a/Demos/Device/RNDISEthernet/Lib/Webserver.c b/Demos/Device/RNDISEthernet/Lib/Webserver.c
new file mode 100644 (file)
index 0000000..c07f2c8
--- /dev/null
@@ -0,0 +1,162 @@
+/*\r
+             LUFA Library\r
+     Copyright (C) Dean Camera, 2009.\r
+              \r
+  dean [at] fourwalledcubicle [dot] com\r
+      www.fourwalledcubicle.com\r
+*/\r
+\r
+/*\r
+  Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
+\r
+  Permission to use, copy, modify, and distribute this software\r
+  and its documentation for any purpose and without fee is hereby\r
+  granted, provided that the above copyright notice appear in all\r
+  copies and that both that the copyright notice and this\r
+  permission notice and warranty disclaimer appear in supporting\r
+  documentation, and that the name of the author not be used in\r
+  advertising or publicity pertaining to distribution of the\r
+  software without specific, written prior permission.\r
+\r
+  The author disclaim all warranties with regard to this\r
+  software, including all implied warranties of merchantability\r
+  and fitness.  In no event shall the author be liable for any\r
+  special, indirect or consequential damages or any damages\r
+  whatsoever resulting from loss of use, data or profits, whether\r
+  in an action of contract, negligence or other tortious action,\r
+  arising out of or in connection with the use or performance of\r
+  this software.\r
+*/\r
+\r
+/** \file\r
+ *\r
+ *  Simple webserver application for demonstrating the RNDIS demo and TCP/IP stack. This\r
+ *  application will serve up a static HTTP webpage when requested by the host.\r
+ */\r
+\r
+#include "Webserver.h"\r
+\r
+/** HTTP server response header, for transmission before the page contents. This indicates to the host that a page exists at the\r
+ *  given location, and gives extra connection information.\r
+ */\r
+char PROGMEM HTTPHeader[] = "HTTP/1.1 200 OK\r\n"\r
+                            "Server: LUFA RNDIS\r\n"\r
+                            "Content-type: text/html\r\n"\r
+                            "Connection: close\r\n\r\n";\r
+\r
+/** HTTP page to serve to the host when a HTTP request is made. This page is too long for a single response, thus it is automatically\r
+ *  broken up into smaller blocks and sent as a series of packets each time the webserver application callback is run.\r
+ */\r
+char PROGMEM HTTPPage[]   = \r
+               "<html>"\r
+               "       <head>"\r
+               "               <title>"\r
+               "                       LUFA Webserver Demo"\r
+               "               </title>"\r
+               "       </head>"\r
+               "       <body>"\r
+               "               <h1>Hello from your USB AVR!</h1>"\r
+               "               <p>"\r
+               "                       Hello! Welcome to the LUFA RNDIS Demo Webserver test page, running on your USB AVR via the LUFA library. This demonstrates the HTTP webserver, TCP/IP stack and RNDIS demo all running atop the LUFA USB stack."\r
+               "                       <br /><br />"\r
+               "                       <small>Project Information: <a href=\"http://www.fourwalledcubicle.com/LUFA.php\">http://www.fourwalledcubicle.com/LUFA.php</a>.</small>"\r
+               "                       <hr />"\r
+               "                       <i>LUFA Version: </i>" LUFA_VERSION_STRING\r
+               "               </p>"\r
+               "       </body>"\r
+               "</html>";\r
+\r
+\r
+/** Initializes the Webserver application, opening the appropriate HTTP port in the TCP handler and registering the application\r
+ *  callback routine for packets sent to the HTTP protocol port.\r
+ */\r
+void Webserver_Init(void)\r
+{\r
+       /* Open the HTTP port in the TCP protocol so that HTTP connections to the device can be established */\r
+       TCP_SetPortState(TCP_PORT_HTTP, TCP_Port_Open, Webserver_ApplicationCallback);\r
+}\r
+\r
+/** Indicates if a given request equals the given HTTP command.\r
+ *\r
+ *  \param RequestHeader  HTTP request made by the host\r
+ *  \param Command        HTTP command to compare the request to\r
+ *\r
+ *  \return Boolean true if the command matches the request, false otherwise\r
+ */\r
+static bool IsHTTPCommand(uint8_t* RequestHeader, char* Command)\r
+{\r
+       /* Returns true if the non null terminated string in RequestHeader matches the null terminated string Command */\r
+       return (strncmp((char*)RequestHeader, Command, strlen(Command)) == 0);\r
+}\r
+\r
+/** Application callback routine, executed each time the TCP processing task runs. This callback determines what request\r
+ *  has been made (if any), and serves up appropriate responses.\r
+ *\r
+ *  \param ConnectionState  Pointer to a TCP Connection State structure giving connection information\r
+ *  \param Buffer           Pointer to the application's send/receive packet buffer\r
+ */\r
+void Webserver_ApplicationCallback(TCP_ConnectionState_t* ConnectionState, TCP_ConnectionBuffer_t* Buffer)\r
+{\r
+       char*          BufferDataStr = (char*)Buffer->Data;\r
+       static uint8_t PageBlock     = 0;\r
+       \r
+       /* Check to see if a packet has been received on the HTTP port from a remote host */\r
+       if (TCP_APP_HAS_RECEIVED_PACKET(Buffer))\r
+       {\r
+               if (IsHTTPCommand(Buffer->Data, "GET"))\r
+               {\r
+                       PageBlock = 0;\r
+\r
+                       /* Copy the HTTP response header into the packet buffer */\r
+                       strcpy_P(BufferDataStr, HTTPHeader);\r
+                       \r
+                       /* Send the buffer contents to the host */\r
+                       TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));\r
+\r
+                       /* Lock the buffer to Device->Host transmissions only while we send the page contents */\r
+                       TCP_APP_CAPTURE_BUFFER(Buffer);\r
+               }\r
+               else if (IsHTTPCommand(Buffer->Data, "HEAD"))\r
+               {\r
+                       /* Copy the HTTP response header into the packet buffer */\r
+                       strcpy_P(BufferDataStr, HTTPHeader);\r
+\r
+                       /* Send the buffer contents to the host */\r
+                       TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));\r
+               }\r
+               else if (IsHTTPCommand(Buffer->Data, "TRACE"))\r
+               {\r
+                       /* Echo the host's query back to the host */\r
+                       TCP_APP_SEND_BUFFER(Buffer, Buffer->Length);\r
+               }\r
+               else\r
+               {\r
+                       /* Unknown request, just clear the buffer (drop the packet) */\r
+                       TCP_APP_CLEAR_BUFFER(Buffer);\r
+               }\r
+       }\r
+       else if (TCP_APP_HAVE_CAPTURED_BUFFER(Buffer))\r
+       {\r
+               uint16_t RemLength = strlen_P(&HTTPPage[PageBlock * HTTP_REPLY_BLOCK_SIZE]);\r
+               uint16_t Length;\r
+       \r
+               /* Determine the length of the loaded block */\r
+               Length = ((RemLength > HTTP_REPLY_BLOCK_SIZE) ? HTTP_REPLY_BLOCK_SIZE : RemLength);\r
+\r
+               /* Copy the next buffer sized block of the page to the packet buffer */\r
+               strncpy_P(BufferDataStr, &HTTPPage[PageBlock * HTTP_REPLY_BLOCK_SIZE], Length);\r
+               \r
+               /* Send the buffer contents to the host */\r
+               TCP_APP_SEND_BUFFER(Buffer, Length);\r
+\r
+               /* Check to see if the entire page has been sent */\r
+               if (PageBlock++ == (sizeof(HTTPPage) / HTTP_REPLY_BLOCK_SIZE))\r
+               {\r
+                       /* Unlock the buffer so that the host can fill it with future packets */\r
+                       TCP_APP_RELEASE_BUFFER(Buffer);\r
+                       \r
+                       /* Close the connection to the host */\r
+                       TCP_APP_CLOSECONNECTION(ConnectionState);\r
+               }\r
+       }\r
+}\r