/* * Code file containing the HTTP Daemon module. * It supports GET (not completely implemented) and POST Request methods * * Author: Simon Kueppers * Email: simon.kueppers@web.de * Homepage: http://klinkerstein.m-faq.de * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Copyright 2008 Simon Kueppers * */ #include #include "HttpD.h" #include "../uip/uip.h" #include "../../Hardware/Gpio.h" #define STATE_CONNECTED 0 //Client has just connected #define STATE_GET_G 1 //G #define STATE_GET_GE 2 //GE #define STATE_GET_GET 3 //GET #define STATE_POST_P 4 //P #define STATE_POST_PO 5 //PO #define STATE_POST_POS 6 //POS #define STATE_POST_POST 7 //POST #define STATE_GOTGET 8 //Client just sent a GET request #define STATE_GOTPOST 9 //Client just sent a POST request #define STATE_PARSEPOST 10 //we are currently parsing the client's POST-data #define STATE_SENDHEADER 11 //next we send him the HTTP header #define STATE_SENDDATA 12 //followed by data #define PARSEBYTES 59 //stop parsing POST data after 59 bytes #define PARSE_CMD 0 #define PARSE_NUM10 1 #define PARSE_NUM1 2 #define PARSE_EQUAL 3 #define PARSE_VAL 4 #define PARSE_DELIM 5 static const prog_char g_HtmlPageDefault[] = "\n" "\n" "" "Home Automation and Security\n" "\n" "\n" "\n" "

Home Automation

\n" "
\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "
GPIO 00OnOff
GPIO 01OnOff
GPIO 02OnOff
GPIO 03OnOff
GPIO 04OnOff
GPIO 05OnOff
GPIO 06OnOff
GPIO 07OnOff
GPIO 08OnOff
GPIO 09 
GPIO 10 
GPIO 11 
GPIO 12 
GPIO 13 
\n" "
\n" "\n"; static uint16_t CopyStringP(uint8_t** ppBuffer, const prog_char* pString) { uint16_t nBytes = 0; char Character; while ((Character = pgm_read_byte(pString)) != '\0') { **ppBuffer = Character; *ppBuffer = *ppBuffer + 1; pString = pString + 1; nBytes++; } return nBytes; } static uint16_t CopyHttpHeader( uint8_t* pBuffer, uint32_t nDataLen) { uint16_t nBytes = 0; nBytes += CopyStringP(&pBuffer, PSTR("HTTP/1.1 200 OK")); nBytes += CopyStringP(&pBuffer, PSTR("\r\n")); //nBytes += CopyStringP(&pBuffer, PSTR("Content-Length:")); //nBytes += CopyValue(&pBuffer, nDataLen); //nBytes += CopyStringP(&pBuffer, PSTR("\r\n")); nBytes += CopyStringP(&pBuffer, PSTR("Content-Type:text/html\r\n")); nBytes += CopyStringP(&pBuffer, PSTR("Connection:close\r\n")); nBytes += CopyStringP(&pBuffer, PSTR("\r\n")); return nBytes; } static uint16_t CopyHttpData( uint8_t* pBuffer, const prog_void** ppData, uint32_t* pDataLeft, uint16_t nMaxBytes) { uint16_t nBytes = 0; uint8_t nByte; uint8_t nParsedNum; uint8_t nParsedMode; while (nMaxBytes--) { if (*pDataLeft > 0) { nByte = pgm_read_byte(*ppData); if (nByte == '%') { *ppData = *ppData + 1; *pDataLeft = *pDataLeft - 1; nParsedMode = pgm_read_byte(*ppData); *ppData = *ppData + 1; *pDataLeft = *pDataLeft - 1; nParsedNum = (pgm_read_byte(*ppData) - '0') * 10; *ppData = *ppData + 1; *pDataLeft = *pDataLeft - 1; nParsedNum += (pgm_read_byte(*ppData) - '0') * 1; if (nParsedMode == 'i') *pBuffer = GpioGetPin(nParsedNum) + '0'; else if (nParsedMode == 'o') *pBuffer = GpioGetPort(nParsedNum) + '0'; else if (nParsedMode == 'd') *pBuffer = GpioGetDdr(nParsedNum) + '0'; } else *pBuffer = nByte; *ppData = *ppData + 1; *pDataLeft = *pDataLeft - 1; pBuffer++; nBytes++; } else break; } return nBytes; } void HttpDInit() { //Start listening on our port uip_listen(HTONS(PORT_HTTPD)); //Set Inputs/Outputs uint8_t i; for (i=0; i<14; i++) { if (i>8) GpioSetDdr(i, 0); else GpioSetDdr(i, 1); } } void HttpDCall( uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) { uint16_t nBufSize; if (uip_connected()) { //Initialize this connection pSocket->pData = g_HtmlPageDefault; pSocket->nDataLeft = sizeof(g_HtmlPageDefault)-1; pSocket->nNewlines = 0; pSocket->nState = STATE_CONNECTED; pSocket->nPrevBytes = 0xFFFF; } else if (uip_newdata() || uip_acked()) { if (pSocket->nState == STATE_CONNECTED) { if (nBytes == 0) return; if (*pBuffer == 'G') pSocket->nState = STATE_GET_G; else if (*pBuffer == 'P') pSocket->nState = STATE_POST_P; nBytes--; pBuffer++; } if (pSocket->nState == STATE_GET_G) { if (nBytes == 0) return; if (*pBuffer == 'E') pSocket->nState = STATE_GET_GE; nBytes--; pBuffer++; } if (pSocket->nState == STATE_GET_GE) { if (nBytes == 0) return; if (*pBuffer == 'T') pSocket->nState = STATE_GET_GET; nBytes--; pBuffer++; } if (pSocket->nState == STATE_GET_GET) { if (nBytes == 0) return; if (*pBuffer == ' ') pSocket->nState = STATE_GOTGET; nBytes--; pBuffer++; } if (pSocket->nState == STATE_POST_P) { if (nBytes == 0) return; if (*pBuffer == 'O') pSocket->nState = STATE_POST_PO; nBytes--; pBuffer++; } if (pSocket->nState == STATE_POST_PO) { if (nBytes == 0) return; if (*pBuffer == 'S') pSocket->nState = STATE_POST_POS; nBytes--; pBuffer++; } if (pSocket->nState == STATE_POST_POS) { if (nBytes == 0) return; if (*pBuffer == 'T') pSocket->nState = STATE_POST_POST; nBytes--; pBuffer++; } if (pSocket->nState == STATE_POST_POST) { if (nBytes == 0) return; if (*pBuffer == ' ') pSocket->nState = STATE_GOTPOST; nBytes--; pBuffer++; } if (pSocket->nState == STATE_GOTPOST || pSocket->nState == STATE_GOTGET) { //Search for \r\n\r\n while (nBytes != 0) { if (*pBuffer == '\n') { pSocket->nNewlines++; } else if (*pBuffer == '\r') { } else { pSocket->nNewlines = 0; } pBuffer++; nBytes--; if (pSocket->nNewlines == 2) { //beginning found. if (pSocket->nState == STATE_GOTPOST) { //Initialize Parsing variables pSocket->nParseLeft = PARSEBYTES; pSocket->ParseState = PARSE_CMD; //start parsing pSocket->nState = STATE_PARSEPOST; } else if (pSocket->nState == STATE_GOTGET) { pSocket->nState = STATE_SENDHEADER; } break; } } } if (pSocket->nState == STATE_PARSEPOST) { while (nBytes--) { if (pSocket->ParseState == PARSE_CMD) { pSocket->ParseCmd = *pBuffer; pSocket->ParseState = PARSE_NUM10; } else if (pSocket->ParseState == PARSE_NUM10) { pSocket->ParseNum = (*pBuffer - '0') * 10; pSocket->ParseState = PARSE_NUM1; } else if (pSocket->ParseState == PARSE_NUM1) { pSocket->ParseNum += (*pBuffer - '0'); pSocket->ParseState = PARSE_EQUAL; } else if (pSocket->ParseState == PARSE_EQUAL) { pSocket->ParseState = PARSE_VAL; } else if (pSocket->ParseState == PARSE_VAL) { if (pSocket->ParseCmd == 'd') GpioSetDdr(pSocket->ParseNum, *pBuffer - '0'); else GpioSetPort(pSocket->ParseNum, *pBuffer - '0'); pSocket->ParseState = PARSE_DELIM; } else if (pSocket->ParseState == PARSE_DELIM) { pSocket->ParseState = PARSE_CMD; } pSocket->nParseLeft--; pBuffer++; if (pSocket->nParseLeft == 0) { //finished parsing pSocket->nState = STATE_SENDHEADER; break; } } } if (pSocket->nState == STATE_SENDHEADER) { uip_send(uip_appdata, CopyHttpHeader(uip_appdata, pSocket->nDataLeft)); pSocket->nState = STATE_SENDDATA; return; } if (pSocket->nState == STATE_SENDDATA) { //We have sent the HTML Header or HTML Data previously. //Now we send (further) Data depending on the Socket's pData pointer //If all data has been sent, we close the connection pSocket->nPrevBytes = pSocket->nDataLeft; nBufSize = CopyHttpData(uip_appdata, &pSocket->pData, &pSocket->nDataLeft, uip_mss()); pSocket->nPrevBytes -= pSocket->nDataLeft; if (nBufSize == 0) { //No Data has been copied. Close connection uip_close(); } else { //Else send copied data uip_send(uip_appdata, nBufSize); } return; } } else if (uip_rexmit()) { if (pSocket->nPrevBytes == 0xFFFF) { /* Send header again */ uip_send(uip_appdata, CopyHttpHeader(uip_appdata, pSocket->nDataLeft)); }else { pSocket->pData -= pSocket->nPrevBytes; pSocket->nDataLeft += pSocket->nPrevBytes; pSocket->nPrevBytes = pSocket->nDataLeft; nBufSize = CopyHttpData(uip_appdata, &pSocket->pData, &pSocket->nDataLeft, uip_mss()); pSocket->nPrevBytes -= pSocket->nDataLeft; if (nBufSize == 0) { //No Data has been copied. Close connection uip_close(); } else { //Else send copied data uip_send(uip_appdata, nBufSize); } } return; } }