/***    GCMD::ACTION ComposeHTMLSDPage(CLIENTINFO * pClientInfo)
 *
 *    Parameters:
 *          pClientInfo - the client info representing this connection and web page
 *              
 *    Return Values:
 *          GCMD::ACTION    - GCMD::CONTINUE, just return with no outside action
 *                          - GCMD::READ, non-blocking read of input data into the rgbIn buffer appended to the end of cbRead
 *                          - GCMD::GETLINE, blocking read until a line of input is read or until the rgbIn buffer is full, always the line starts at the beginnig of the rgbIn
 *                          - GCMD::WRITE, loop writing until all cbWrite bytes are written from the pbOut buffer
 *                          - GCMD::DONE, we are done processing and the connection can be closed
 *
 *    Description: 
 *    
 *      This renders a page off of the SD filesystem. Pages of type
 *      .htm, .html, .jpeg, .png, .txt and more may be rendered
 *      The file extension on the filename determine the MIME type
 *      returned to the client.
 *    
 * ------------------------------------------------------------ */
GCMD::ACTION ComposeHTMLSDPage(CLIENTINFO * pClientInfo)
{
    char * pFileNameEnd     = NULL;

    GCMD::ACTION retCMD = GCMD::CONTINUE;

    switch(pClientInfo->htmlState)
    {
        case HTTPSTART:

            if(pClientMutex != NULL || (sdLockId = lockSD()) == SDUNLOCKED)
            {
                break;
            }
            pClientMutex = pClientInfo;

            Serial.println("Read an HTML page off of the SD card");

            Serial.print("Entering Client ID: 0x");
            Serial.println((uint32_t) pClientMutex, HEX);

            pClientInfo->htmlState = PARSEFILENAME;
            retCMD = GCMD::GETLINE;
            break;

        case PARSEFILENAME:

            // the assumption is that the file name will be on the first line of the command
            // there is a bunch of other stuff on the line we don't care about, but it is at the
            // end of the line.
            Serial.println((char *) pClientInfo->rgbIn);

            // find the begining of the file name
            szFileName = strstr((const char *) pClientInfo->rgbIn, szGET);
            if(szFileName == NULL)
            {
                pClientInfo->htmlState = JMPFILENOTFOUND;
                break;
            }
            szFileName += sizeof(szGET) - 1;

            // find the end of the file name
            pFileNameEnd = strstr(szFileName, szEndOfURL);

            if(pFileNameEnd == NULL)
            {
                pClientInfo->htmlState = JMPFILENOTFOUND;
                break;
            }
            else if(pFileNameEnd == szFileName)
            {
                szFileName = szDefaultPage;
            }
            else
            {
                *pFileNameEnd = '\0';
            }

            Serial.print("SD FileName:");
            Serial.println(szFileName);

            if(dFile.fsopen(szFileName, FA_READ) == FR_OK)
            {
                Serial.print("HTML page:");
                Serial.print(szFileName);
                Serial.println(" exists!");
                pClientInfo->htmlState = BUILDHTTP;
            }

            else
            {
                Serial.print("Unable to find HTML page:");
                Serial.println(szFileName);
                pClientInfo->htmlState = JMPFILENOTFOUND;
            }
            break;

        // We need to build the HTTP directive
        case BUILDHTTP:

            if(dFile && (dFile.fslseek(0) == FR_OK))
            {
                pClientInfo->cbWrite = BuildHTTPOKStr(false, dFile.fssize(), szFileName, (char *) pClientInfo->rgbOut, sizeof(pClientInfo->rgbOut));
                if(pClientInfo->cbWrite > 0)
                {
                    pClientInfo->pbOut = pClientInfo->rgbOut;
                    retCMD = GCMD::WRITE;
                    pClientInfo->htmlState = SENDFILE;
                    cbSent = 0;
                    tStart = millis();

                    Serial.print("Writing file:");
                    Serial.println(szFileName);
                }
                else
                {
                    Serial.print("Unable to build HTTP directive for file:");
                    Serial.println(szFileName);
                    pClientInfo->htmlState = JMPFILENOTFOUND;
                }
            }
            else
            {
                Serial.print("Unable to open HTML page:");
                Serial.println(szFileName);
                pClientInfo->htmlState = JMPFILENOTFOUND;
            }
            break;

        // Send the file
        case SENDFILE:
            {
                uint32_t    cbT = 0;

                if((cbT = SDRead(dFile, pClientInfo->rgbOut, sizeof(pClientInfo->rgbOut))) > 0)
                {
                    cbSent += cbT;
                    pClientInfo->pbOut = pClientInfo->rgbOut;
                    pClientInfo->cbWrite = cbT;
                    tStart = millis();
                    retCMD = GCMD::WRITE;
                }
                else if(cbSent == dFile.fssize())
                {
                   pClientInfo->htmlState = EXIT;
                }
                else if((millis() - tStart) > SDREADTIMEOUT)
                {
                   pClientInfo->htmlState = HTTPTIMEOUT;
                }
            }
            break;
    
         case EXIT:
            Serial.println("Wrote page cleanly");
            pClientInfo->htmlState = HTTPDISCONNECT;
            break;

        case JMPFILENOTFOUND:
            Serial.println("Jumping to HTTP File Not Found page");

            if(isMySD(sdLockId))
            {
                if(dFile)
                {
                    dFile.fsclose();
                }
                sdLockId = unlockSD(sdLockId);
            }
            pClientMutex = NULL;
            return(JumpToComposeHTMLPage(pClientInfo, ComposeHTTP404Error));
            break;

        case HTTPTIMEOUT:
            Serial.println("Timeout error occured, closing the session");

            // fall thru to close

        case HTTPDISCONNECT:
            if(pClientMutex == pClientInfo)
            {
                Serial.print("Closing Client ID: 0x");
                Serial.println((uint32_t) pClientMutex, HEX);
                if(isMySD(sdLockId))
                {
                    if(dFile)
                    {
                        dFile.fsclose();
                    }
                    sdLockId = unlockSD(sdLockId);
                }
                pClientMutex = NULL;
            }
            // fall thru Done

        case DONE:
        default:
            pClientInfo->cbWrite = 0;
            retCMD = GCMD::DONE;
            break;
    }

    return(retCMD);
}
示例#2
0
/***    GCMD::ACTION ComposeHTMLGetIO(CLIENTINFO * pClientInfo)
 *
 *    Parameters:
 *          pClientInfo - the client info representing this connection and web page
 *
 *    Return Values:
 *          GCMD::ACTION    - GCMD::CONTINUE, just return with no outside action
 *                          - GCMD::READ, non-blocking read of input data into the rgbIn buffer appended to the end of cbRead
 *                          - GCMD::GETLINE, blocking read until a line of input is read or until the rgbIn buffer is full, always the line starts at the beginnig of the rgbIn
 *                          - GCMD::WRITE, loop writing until all cbWrite bytes are written from the pbOut buffer
 *                          - GCMD::DONE, we are done processing and the connection can be closed
 *
 *    Description:
 *
 *      This renders a page of the LEDs, BTNs, or SWTs on the device
 *      It reads a template page from the SD card, puts it into a temp
 *      RAM buffer, and then updates the template with acutal values
 * ------------------------------------------------------------ */
GCMD::ACTION ComposeHTMLGetIO(CLIENTINFO * pClientInfo)
{
    char * pFileNameEnd     = NULL;

    GCMD::ACTION retCMD = GCMD::CONTINUE;

    switch(pClientInfo->htmlState)
    {
    case HTTPSTART:

        // serialize so we only do this page once at a time
        // this protects the szPageBuffer
        if(pClientMutex != NULL)
        {
            break;
        }
        pClientMutex = pClientInfo;

        Serial.println("Get IO Page Detected");

        Serial.print("Entering Client ID: 0x");
        Serial.println((uint32_t) pClientMutex, HEX);

        pClientInfo->htmlState = READTEMPLATE;
        break;

    // Read the template htm
    case READTEMPLATE:

        // We want to serialize usage to the SD card
        if((sdLockId = lockSD()) == SDUNLOCKED)
        {
            break;
        }

        // open the templeate file
        if((fileSD = SD.open(szIOPage, FILE_READ)) && fileSD.seek(0) )
        {
            // because we have the SD file data now, build the HTTP header in the output temp buffer
            // we will only use this if all goes well.
            // this will be held for 2 states
            cbFile = fileSD.size();
            pClientInfo->cbWrite = BuildHTTPOKStr(false, cbFile, szIOPage, (char *) pClientInfo->rgbOut, sizeof(pClientInfo->rgbOut));

            // since szIOPage is a template .htm, this better always be true!
            if( 0 < cbFile && cbFile < sizeof(szPageBuffer) && SDRead(fileSD, (uint8_t *) szPageBuffer, cbFile) == cbFile )
            {

                // That Read could have takin some time, so lets release and pick up
                // on another state
                szPageBuffer[cbFile] = '\0';
                iReplace = 0;
                pchLast = szPageBuffer;
                pClientInfo->htmlState = REPLACE;
            }

            // not good, not expected either
            else
            {
                Serial.print("Unable to build HTTP directive for file:");
                Serial.println(szIOPage);
                Serial.print("Sizeof ");
                Serial.print(szIOPage);
                Serial.print(" is ");
                Serial.print(cbFile, DEC);
                Serial.println(" bytes");
                Serial.print("Sizeof page buffer is");
                Serial.print(sizeof(szPageBuffer), DEC);
                Serial.println(" bytes");
                pClientInfo->htmlState = JMPFILENOTFOUND;
            }
        }

        // something is wrong with the SD card; which happens  :-(
        else
        {
            Serial.print("Unable to open HTML page:");
            Serial.println(szIOPage);
            pClientInfo->htmlState = JMPFILENOTFOUND;
        }

        // no matter what, were are done with the SD Card
        fileSD.close();
        sdLockId = unlockSD(sdLockId);
        break;

    case REPLACE:

        // do our replacentments one string at a time.
        if(iReplace < cReplacementStrings)
        {
            if((pchLast = strstr(pchLast, szReplaceStr)) == NULL)
            {
                // oh this is not good, something is wrong with the template file
                Serial.print("Unable able to find template replacemnt on index ");
                Serial.print(iReplace, DEC);
                Serial.print(" in template file ");
                Serial.println(szIOPage);
                pClientInfo->htmlState = JMPFILENOTFOUND;
            }
            else
            {
                bool isOn = digitalRead(rgReplacePins[iReplace]);

                if(iReplace < HTTPCIO)
                {
                    if(isOn)
                    {
                        memcpy(pchLast, szON, sizeof(szON)-1);
                    }
                    else
                    {
                        memcpy(pchLast, szOFF, sizeof(szOFF)-1);
                    }
                }
                else if((iReplace - HTTPCIO) < HTTPCLED)
                {
                    if(isOn)
                    {
                        memcpy(pchLast, szChecked, sizeof(szChecked)-1);
                    }
                    else
                    {
                        memcpy(pchLast, szUnChecked, sizeof(szUnChecked)-1);
                    }
                }

                // do the next replacement string.
                iReplace++;
            }
        }

        // time to start writing stuff out, first the HTTP header that has
        // been sitting in pClientInfo->rgbOut
        else
        {
            pClientInfo->pbOut = pClientInfo->rgbOut;
            retCMD = GCMD::WRITE;
            pClientInfo->htmlState = SENDFILE;
        }
        break;

    // Send the file
    case SENDFILE:
        pClientInfo->cbWrite = cbFile;
        pClientInfo->pbOut = (byte *) szPageBuffer;
        retCMD = GCMD::WRITE;
        pClientInfo->htmlState = EXIT;
        break;

    case EXIT:
        Serial.println("Wrote page cleanly");
        pClientInfo->htmlState = HTTPDISCONNECT;
        break;

    case JMPFILENOTFOUND:
        Serial.println("Jumping to HTTP File Not Found page");
        pClientMutex = NULL;
        return(JumpToComposeHTMLPage(pClientInfo, ComposeHTTP404Error));
        break;

    case HTTPTIMEOUT:
        Serial.println("Timeout error occured, closing the session");

    // fall thru to close

    case HTTPDISCONNECT:
        if(pClientMutex == pClientInfo)
        {
            Serial.print("Closing Client ID: 0x");
            Serial.println((uint32_t) pClientMutex, HEX);
            pClientMutex = NULL;
        }
    // fall thru Done

    case DONE:
    default:
        pClientInfo->cbWrite = 0;
        retCMD = GCMD::DONE;
        break;
    }

    return(retCMD);
}