Host library for controlling a WiConnect enabled Wi-Fi module.

Dependents:   wiconnect-ota_example wiconnect-web_setup_example wiconnect-test-console wiconnect-tcp_server_example ... more

WiconnectFile.cpp

Committer:
dan_ackme
Date:
2014-10-27
Revision:
29:b6af04b77a56

File content as of revision 29:b6af04b77a56:

/**
 * ACKme WiConnect Host Library is licensed under the BSD licence: 
 * 
 * Copyright (c)2014 ACKme Networks.
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met: 
 * 
 * 1. Redistributions of source code must retain the above copyright notice, 
 * this list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the documentation 
 * and/or other materials provided with the distribution. 
 * 3. The name of the author may not be used to endorse or promote products 
 * derived from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 */

#include "Wiconnect.h"
#include "internal/common.h"

#define CHECK_OPENED_FOR_READING() if(!readEnabled) return WICONNECT_NOT_OPENED_FOR_READING




/*************************************************************************************************/
WiconnectFile::WiconnectFile(int rxBufferLen, void *rxBuffer_)
{
    wiconnect = Wiconnect::getInstance();

    memset(&rxBuffer, 0, sizeof(Buffer));

    rxBuffer.size = rxBufferLen - 4;
    rxBuffer.buffer = (uint8_t*)rxBuffer_;

    if(rxBuffer.size > 0)
    {
        if(rxBuffer_ == NULL)
        {
#ifdef WICONNECT_ENABLE_MALLOC
            wiconnect_assert(wiconnect, "File(), malloc not defined", wiconnect->_malloc != NULL);
            rxBuffer.buffer = (uint8_t*)wiconnect->_malloc(rxBufferLen);
            wiconnect_assert(wiconnect, "File(), failed to malloc buffer", rxBuffer.buffer != NULL);
            rxBuffer.allocated = true;
#else
            wiconnect_assert(wiconnect, "must specify buffer", 0);
#endif
        }
        rxBuffer.size -= 4;
    }

    previous = next = NULL;
    handle = 0xff;
    readEnabled = false;
    *name = 0;
    size = 0;
    type = FILE_TYPE_UNKNOWN;
    version = 0;
    flags = FILE_FLAG_NONE;
}

/*************************************************************************************************/
WiconnectFile::~WiconnectFile()
{
    while(close() == WICONNECT_PROCESSING)
    {
    }

#ifdef WICONNECT_ENABLE_MALLOC
    if(rxBuffer.allocated && rxBuffer.size > 0)
    {
        wiconnect_assert(wiconnect, "~File(), free not defined", wiconnect->_free != NULL);
        wiconnect->_free(rxBuffer.buffer);
    }
#endif
}

/*************************************************************************************************/
WiconnectResult WiconnectFile::openForRead(uint8_t handle_, const char *filename)
{
    handle = handle_;
    readEnabled = true;
    strcpy(name, filename);

    return WICONNECT_SUCCESS;
}

/*************************************************************************************************/
WiconnectResult WiconnectFile::initWithListing(const char *typeStr, const char *flagsStr, const char* sizeStr, const char *versionStr, const char *nameStr)
{
    uint32_t tmp;

    if(!StringUtil::strHexToUint32(&typeStr[2], &tmp))
    {
        return WICONNECT_RESPONSE_PARSE_ERROR;
    }
    type = (FileType)tmp;

    if(!StringUtil::strHexToUint32(flagsStr, &tmp))
    {
        return WICONNECT_RESPONSE_PARSE_ERROR;
    }
    flags = (FileFlags)tmp;

    if(!StringUtil::strToUint32(sizeStr, &tmp))
    {
        return WICONNECT_RESPONSE_PARSE_ERROR;
    }
    size = (uint32_t)tmp;

    if(!FileInterface::fileVersionStrToInt(versionStr, &version))
    {
        return WICONNECT_RESPONSE_PARSE_ERROR;
    }

    strcpy(name, nameStr);

    return WICONNECT_SUCCESS;
}

#ifdef WICONNECT_ENABLE_MALLOC
/*************************************************************************************************/
void* WiconnectFile::operator new(size_t size)
{
    Wiconnect *wiconnect = Wiconnect::getInstance();
    wiconnect_assert(wiconnect, "File:new, malloc not defined", wiconnect->_malloc != NULL);
    return Wiconnect::getInstance()->_malloc(size);
}

/*************************************************************************************************/
void WiconnectFile::operator delete(void* ptr)
{
    Wiconnect *wiconnect = Wiconnect::getInstance();
    wiconnect_assert(wiconnect, "File:delete, free not defined", wiconnect->_free != NULL);
    Wiconnect::getInstance()->_free(ptr);
}
#endif

/*************************************************************************************************/
WiconnectResult WiconnectFile::close()
{
    WiconnectResult result;
    CHECK_OPENED_FOR_READING();
    CHECK_OTHER_COMMAND_EXECUTING();

    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("close %d", handle)))
    {
        readEnabled = false;
    }

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
const char* WiconnectFile::getName() const
{
    return name;
}

/*************************************************************************************************/
uint32_t WiconnectFile::getSize() const
{
    return size;
}

/*************************************************************************************************/
FileType WiconnectFile::getType() const
{
    return type;
}

/*************************************************************************************************/
FileFlags WiconnectFile::getFlags() const
{
    return flags;
}

/*************************************************************************************************/
uint32_t WiconnectFile::getVersion() const
{
    return version;
}

/*************************************************************************************************/
const char* WiconnectFile::getVersionStr(char *buffer) const
{
    return FileInterface::fileVersionIntToStr(version, true, buffer);
}

/*************************************************************************************************/
const WiconnectFile* WiconnectFile::getNext() const
{
    return next;
}

/*************************************************************************************************/
const WiconnectFile* WiconnectFile::getPrevious() const
{
    return previous;
}


/*************************************************************************************************/
WiconnectResult WiconnectFile::read(void* buffer, uint16_t maxLength, uint16_t *bytesReadPtr)
{
    WiconnectResult result;

    CHECK_OPENED_FOR_READING();

    if(rxBuffer.size > 0)
    {
        uint16_t bytesToRead = 0;
        const uint16_t bufferedBytes = (&rxBuffer.buffer[rxBuffer.bytesPending] - rxBuffer.ptr);
        if(bufferedBytes > 0)
        {
            bytesToRead = MIN(bufferedBytes, maxLength);
            memcpy(buffer, rxBuffer.ptr, bytesToRead);
            rxBuffer.ptr += bytesToRead;
            *bytesReadPtr = bytesToRead;
        }
        if(rxBuffer.ptr >= &rxBuffer.buffer[rxBuffer.bytesPending])
        {
            clearRxBuffer();
        }
        if(bytesToRead > 0)
        {
            return WICONNECT_SUCCESS;
        }
    }

    CHECK_OTHER_COMMAND_EXECUTING();

    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand((char*)buffer, maxLength, "read %d %d", handle, maxLength)))
    {
        *bytesReadPtr = wiconnect->getLastCommandResponseLength();
    }

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
WiconnectResult WiconnectFile::read(uint8_t **bufferPtr, uint16_t *bytesReadPtr)
{
    WiconnectResult result = WICONNECT_SUCCESS;

    CHECK_OPENED_FOR_READING();

    if(rxBuffer.size == 0)
    {
        return WICONNECT_UNSUPPORTED;
    }
    else if(bufferPtr != NULL && bytesReadPtr == NULL)
    {
        return WICONNECT_BAD_ARG;
    }

    if(rxBuffer.ptr >= &rxBuffer.buffer[rxBuffer.bytesPending])
    {
        clearRxBuffer();
    }


    if(rxBuffer.bytesPending < rxBuffer.size)
    {
        const int bytesToRead = rxBuffer.size - rxBuffer.bytesPending;
        char* ptr = (char*)&rxBuffer.buffer[rxBuffer.bytesPending];

        CHECK_OTHER_COMMAND_EXECUTING();

        loop:
        if(bytesToRead > 0 && WICONNECT_SUCCEEDED(result, wiconnect->sendCommand(ptr, bytesToRead, "read %d %d", handle, bytesToRead)))
        {
            const uint16_t bytesRead = wiconnect->getLastCommandResponseLength();
            rxBuffer.bytesPending += bytesRead;
        }

        // if still processing and in non-blocking mode,
        // then this api call must block until the command completes
        if(result == WICONNECT_PROCESSING && wiconnect->nonBlocking)
        {
            goto loop;
        }

        CHECK_CLEANUP_COMMAND();
    }

    if(bufferPtr != NULL)
    {
        *bufferPtr = rxBuffer.buffer;
        *bytesReadPtr = rxBuffer.bytesPending;
        clearRxBuffer();
    }

    return result;
}

/*************************************************************************************************/
WiconnectResult WiconnectFile::getc(uint8_t *c)
{
    WiconnectResult result;

    if(rxBuffer.size == 0)
    {
        return WICONNECT_UNSUPPORTED;
    }

    if(rxBuffer.bytesPending == 0 &&
      WICONNECT_FAILED(result, read()))
    {
        return result;
    }
    else if(rxBuffer.ptr < &rxBuffer.buffer[rxBuffer.bytesPending])
    {
        *c = *rxBuffer.ptr;
        ++rxBuffer.ptr;
        return WICONNECT_SUCCESS;
    }
    else
    {
        clearRxBuffer();
        return WICONNECT_ERROR;
    }
}

/*************************************************************************************************/
void WiconnectFile::clearRxBuffer()
{
    rxBuffer.bytesPending = 0;
    rxBuffer.ptr = rxBuffer.buffer;
}