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

Revision:
0:ea85c4bb5e1f
Child:
1:6ec9998427ad
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/internal/types/Socket.cpp	Mon Aug 11 09:58:24 2014 +0000
@@ -0,0 +1,490 @@
+/*
+ * Copyright 2014, ACKme Networks
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of ACKme Networks;
+ * the contents of this file may not be disclosed to third parties, copied
+ * or duplicated in any form, in whole or in part, without the prior
+ * written permission of ACKme Networks.
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include "Wiconnect.h"
+#include "internal/common.h"
+#include "StringUtil.h"
+
+
+#define CHECK_CONNECTED() if(!isConnected()) return WICONNECT_NOT_CONNECTED
+
+
+/*************************************************************************************************/
+Socket::Socket(int rxBufferLen_, void *rxBuffer_, int txBufferLen_, void *txBuffer_)
+{
+    wiconnect = Wiconnect::getInstance();
+
+    memset(&txBuffer, 0, sizeof(Buffer));
+    memset(&rxBuffer, 0, sizeof(Buffer));
+
+    txBuffer.size = !wiconnect->nonBlocking ? txBufferLen_ : 0;
+    txBuffer.buffer = (uint8_t*)txBuffer_;
+
+    rxBuffer.size = !wiconnect->nonBlocking ? rxBufferLen_ : 0;
+    rxBuffer.buffer = (uint8_t*)rxBuffer_;
+
+    if(txBuffer.size > 0)
+    {
+        if(txBuffer_ == NULL)
+        {
+#ifdef WICONNECT_ENABLE_MALLOC
+            assert(wiconnect->_malloc != NULL);
+            txBuffer.buffer = (uint8_t*)wiconnect->_malloc(txBufferLen_);
+            assert(txBuffer.buffer != NULL);
+            txBuffer.allocated = true;
+#else
+            assert(0);
+#endif
+        }
+    }
+
+    if(rxBuffer.size > 0)
+    {
+        if(rxBuffer_ == NULL)
+        {
+#ifdef WICONNECT_ENABLE_MALLOC
+            assert(wiconnect->_malloc != NULL);
+            rxBuffer.buffer = (uint8_t*)wiconnect->_malloc(rxBufferLen_);
+            assert(rxBuffer.buffer != NULL);
+            rxBuffer.allocated = true;
+#else
+            assert(0);
+#endif
+        }
+    }
+
+    init(SOCKET_INVALID_HANDLE, SOCKET_TYPE_UNKNOWN, NULL, 0, 0);
+}
+
+
+/*************************************************************************************************/
+WiconnectResult Socket::init(uint8_t handle_, SocketType type_, const char *host_, uint16_t remotePort_, uint16_t localPort_)
+{
+    handle = handle_;
+    type = type_;
+    remotePort = remotePort_;
+    localPort = localPort_;
+    connected = true;
+
+    txBuffer.ptr = txBuffer.buffer;
+    rxBuffer.ptr = rxBuffer.buffer;
+
+    strncpy(host, host_, sizeof(host)-1);
+
+    return WICONNECT_SUCCESS;
+}
+
+/*************************************************************************************************/
+Socket::~Socket()
+{
+    while((handle != SOCKET_INVALID_HANDLE) && (close() == WICONNECT_PROCESSING))
+    {
+    }
+
+#ifdef WICONNECT_ENABLE_MALLOC
+    if(txBuffer.allocated && txBuffer.size > 0)
+    {
+        assert(wiconnect->_free != NULL);
+        wiconnect->_free(txBuffer.buffer);
+    }
+    if(rxBuffer.allocated && rxBuffer.size > 0)
+    {
+        assert(wiconnect->_free != NULL);
+        wiconnect->_free(rxBuffer.buffer);
+    }
+#endif
+}
+
+/*************************************************************************************************/
+bool Socket::isConnected()
+{
+    return connected;
+}
+
+/*************************************************************************************************/
+SocketType Socket::getType()
+{
+    return type;
+}
+
+/*************************************************************************************************/
+const char* Socket::getHost()
+{
+    return host;
+}
+
+/*************************************************************************************************/
+uint16_t Socket::getLocalPort()
+{
+    return localPort;
+}
+
+/*************************************************************************************************/
+uint16_t Socket::getRemotePort()
+{
+    return remotePort;
+}
+
+/*************************************************************************************************/
+uint8_t Socket::getHandle()
+{
+    return handle;
+}
+
+
+/*************************************************************************************************/
+WiconnectResult Socket::close()
+{
+    WiconnectResult result;
+    CHECK_CONNECTED();
+    CHECK_OTHER_COMMAND_EXECUTING();
+
+    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("close %d", handle)))
+    {
+        connected = false;
+    }
+
+    CHECK_CLEANUP_COMMAND();
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult Socket::poll(bool *rxDataAvailablePtr)
+{
+    WiconnectResult result;
+    int32_t status;
+
+    CHECK_CONNECTED();
+    CHECK_OTHER_COMMAND_EXECUTING();
+
+    *rxDataAvailablePtr = false;
+
+    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("poll %d", handle)))
+    {
+        if(!WICONNECT_FAILED(result, wiconnect->responseToInt32(&status)))
+        {
+            if(status == 2)
+            {
+                connected = false;
+            }
+            else if(status == 1)
+            {
+                *rxDataAvailablePtr = true;
+            }
+        }
+    }
+
+    CHECK_CLEANUP_COMMAND();
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult Socket::write(int length, bool flush)
+{
+    CHECK_CONNECTED();
+
+    if( txBuffer.size == 0)
+    {
+        return WICONNECT_UNSUPPORTED;
+    }
+    else if(length > txBuffer.size)
+    {
+        return WICONNECT_OVERFLOW;
+    }
+    txBuffer.bytesPending = length;
+
+    return flush ? flushTxBuffer() : WICONNECT_SUCCESS;
+}
+
+/*************************************************************************************************/
+WiconnectResult Socket::write(const void* buffer, int length, bool flush)
+{
+    WiconnectResult result = WICONNECT_SUCCESS;
+    CHECK_CONNECTED();
+
+    if(txBuffer.size > 0)
+    {
+        // NOTE: txBuffer only available in blocking mode (so no need to check if a cmd is executing)
+
+        const uint8_t *src = (const uint8_t *)buffer;
+
+        while(length > 0)
+        {
+            int bytesToWrite = MIN(length, txBuffer.size - txBuffer.bytesPending);
+            uint8_t *dst = (uint8_t*)&txBuffer.buffer[txBuffer.bytesPending];
+            memcpy(dst, src, bytesToWrite);
+            txBuffer.bytesPending += bytesToWrite;
+            length -= bytesToWrite;
+            src += bytesToWrite;
+
+            if((txBuffer.bytesPending >= txBuffer.size) &&
+                WICONNECT_FAILED(result, flushTxBuffer()))
+            {
+                 break;
+            }
+        }
+
+        if(flush && txBuffer.bytesPending > 0)
+        {
+            result = flushTxBuffer();
+        }
+    }
+    else
+    {
+        if(WICONNECT_IS_IDLE())
+        {
+            txBuffer.ptr = (uint8_t*)buffer;
+            txBuffer.bytesPending = length;
+        }
+
+        result = flushTxBuffer();
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult Socket::read(void* buffer, uint16_t maxLength, uint16_t *bytesRead)
+{
+    WiconnectResult result;
+
+    CHECK_CONNECTED();
+    CHECK_OTHER_COMMAND_EXECUTING();
+
+    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand((char*)buffer, maxLength, "read %d %d", handle, maxLength-2)))
+    {
+        *bytesRead = wiconnect->getLastCommandResponseLength();
+    }
+
+    CHECK_CLEANUP_COMMAND();
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult Socket::read(uint8_t **bufferPtr, uint16_t *bytesReadPtr)
+{
+    WiconnectResult result = WICONNECT_SUCCESS;
+
+    CHECK_CONNECTED();
+
+    if(rxBuffer.size == 0)
+    {
+        return WICONNECT_UNSUPPORTED;
+    }
+    else if(bufferPtr != NULL && bytesReadPtr == NULL)
+    {
+        return WICONNECT_BAD_ARG;
+    }
+    else if(rxBuffer.bytesPending < rxBuffer.size - 2)
+    {
+        const int bytesToRead = rxBuffer.size - rxBuffer.bytesPending - 2;
+        char* ptr = (char*)&rxBuffer.buffer[rxBuffer.bytesPending];
+        if(!WICONNECT_FAILED(result, wiconnect->sendCommand(ptr, bytesToRead+2, "read %d %d", handle, bytesToRead)))
+        {
+            rxBuffer.bytesPending += wiconnect->getLastCommandResponseLength();
+        }
+    }
+
+    if(bufferPtr != NULL)
+    {
+        *bufferPtr = rxBuffer.buffer;
+        *bytesReadPtr = rxBuffer.bytesPending;
+        clearRxBuffer();
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult Socket::getc(uint8_t *c)
+{
+    WiconnectResult result;
+
+    if(rxBuffer.size == 0)
+    {
+        return WICONNECT_UNSUPPORTED;
+    }
+
+    read_data:
+    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();
+        goto read_data;
+    }
+}
+
+/*************************************************************************************************/
+WiconnectResult Socket::putc(uint8_t c, bool flush)
+{
+    WiconnectResult result = WICONNECT_SUCCESS;
+    CHECK_CONNECTED();
+
+    if(txBuffer.size == 0)
+    {
+        return WICONNECT_UNSUPPORTED;
+    }
+    else if(txBuffer.bytesPending < txBuffer.size)
+    {
+        uint8_t *ptr = (uint8_t*)&txBuffer.buffer[txBuffer.bytesPending];
+        *ptr = c;
+        ++txBuffer.bytesPending;
+
+        if(flush || txBuffer.bytesPending >= txBuffer.size)
+        {
+            result = flushTxBuffer();
+        }
+    }
+    else
+    {
+        result = WICONNECT_OVERFLOW;
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult Socket::puts(const char *s, bool flush)
+{
+    const int len = strlen(s);
+    return write(s, len, flush);
+}
+
+/*************************************************************************************************/
+WiconnectResult Socket::printf(const char* format, ...)
+{
+    WiconnectResult result = WICONNECT_SUCCESS;
+
+    CHECK_CONNECTED();
+    if(txBuffer.size == 0)
+    {
+        return WICONNECT_UNSUPPORTED;
+    }
+
+    const int available = txBuffer.size - txBuffer.bytesPending;
+    char *ptr = (char*)&txBuffer.buffer[txBuffer.bytesPending];
+    va_list args;
+    va_start(args, format);
+    const int len = vsnprintf(ptr, available, format, args);
+    if(len > available)
+    {
+        return WICONNECT_OVERFLOW;
+    }
+    else
+    {
+        txBuffer.bytesPending += len;
+    }
+
+    if(txBuffer.bytesPending >= txBuffer.size)
+    {
+        result = flushTxBuffer();
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult Socket::flushTxBuffer()
+{
+    WiconnectResult result = WICONNECT_SUCCESS;
+
+    CHECK_CONNECTED();
+    CHECK_OTHER_COMMAND_EXECUTING();
+
+    if(txBuffer.bytesPending > 0)
+    {
+        result = wiconnect->sendCommand(ReaderFunc(this, &Socket::writeDataCallback), NULL, "write %d %d", handle, txBuffer.bytesPending);
+    }
+
+    CHECK_CLEANUP_COMMAND();
+
+    if(result != WICONNECT_PROCESSING)
+    {
+        txBuffer.ptr = txBuffer.buffer;
+        txBuffer.bytesPending = 0;
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+void Socket::clearRxBuffer()
+{
+    rxBuffer.bytesPending = 0;
+    rxBuffer.ptr = rxBuffer.buffer;
+}
+
+/*************************************************************************************************/
+uint8_t* Socket::getTxBuffer()
+{
+    return txBuffer.buffer;
+}
+/*************************************************************************************************/
+int Socket::getTxBufferSize()
+{
+    return txBuffer.size;
+}
+/*************************************************************************************************/
+int Socket::getTxBufferBytesPending()
+{
+    return txBuffer.bytesPending;
+}
+/*************************************************************************************************/
+uint8_t* Socket::getRxBuffer()
+{
+    return rxBuffer.buffer;
+}
+/*************************************************************************************************/
+int Socket::getRxBufferSize()
+{
+    return rxBuffer.size;
+}
+/*************************************************************************************************/
+int Socket::getRxBufferBytesPending()
+{
+    return rxBuffer.bytesPending;
+}
+
+
+/*************************************************************************************************/
+WiconnectResult Socket::writeDataCallback(void *user, void *data, int maxReadSize, int *bytesRead)
+{
+    if(txBuffer.bytesPending == 0)
+    {
+        *bytesRead = EOF;
+    }
+    else
+    {
+        int bytesToWrite = MIN(maxReadSize, txBuffer.bytesPending);
+        memcpy(data, txBuffer.ptr, bytesToWrite);
+        txBuffer.ptr += bytesToWrite;
+        txBuffer.bytesPending -= bytesToWrite;
+        *bytesRead = bytesToWrite;
+    }
+
+    return WICONNECT_SUCCESS;
+}
+
+