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:
29:b6af04b77a56
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProcessCommand.cpp	Mon Oct 27 13:42:26 2014 -0700
@@ -0,0 +1,356 @@
+/**
+ * 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 "internal/CommandCommon.h"
+
+
+
+/*************************************************************************************************/
+WiconnectResult Wiconnect::checkCurrentCommand()
+{
+    WiconnectResult result;
+
+    start:
+    CHECK_INITIALIZED();
+    if(!commandExecuting)
+    {
+        return WICONNECT_IDLE;
+    }
+    CommandContext *context = (CommandContext*)commandContext;
+
+    if(context->commandLen > 0)
+    {
+        const TimerTimeout timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs);
+        const int bytesToWrite = context->commandLen;
+        const int bytesWritten = serial.write(context->commandPtr, bytesToWrite, timeout);
+        context->commandPtr += bytesWritten;
+        context->commandLen -= bytesWritten;
+        if(bytesToWrite != bytesWritten)
+        {
+            if(timeoutTimer.timedOut(context->timeoutMs))
+            {
+                issueCommandCallback(WICONNECT_TIMEOUT);
+                return WICONNECT_TIMEOUT;
+            }
+            else
+            {
+                return WICONNECT_PROCESSING;
+            }
+        }
+    }
+
+    while(context->reader.isValid())
+    {
+        if(context->bytesToWrite == 0)
+        {
+            context->responseBufferPtr = context->responseBuffer;
+            if(WICONNECT_FAILED(result, context->reader.call(context->user, context->responseBuffer, context->responseBufferLen, &context->bytesToWrite)))
+            {
+                issueCommandCallback(result);
+                return result;
+            }
+            else if(context->bytesToWrite == EOF)
+            {
+                context->reader.setInvalid();
+                context->bytesToWrite = 0;
+                context->responseBufferPtr = context->responseBuffer;
+                break;
+            }
+            else
+            {
+                timeoutTimer.reset();
+            }
+        }
+        if(context->bytesToWrite > 0)
+        {
+            const TimerTimeout timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs);
+            const int bytesToWrite = context->bytesToWrite;
+            const int bytesWritten = serial.write(context->responseBufferPtr, bytesToWrite, timeout);
+            context->responseBufferPtr += bytesWritten;
+            context->bytesToWrite -= bytesWritten;
+            if(bytesToWrite != bytesWritten)
+            {
+                if(timeoutTimer.timedOut(context->timeoutMs))
+                {
+                    issueCommandCallback(WICONNECT_TIMEOUT);
+                    return WICONNECT_TIMEOUT;
+                }
+                else
+                {
+                    return WICONNECT_PROCESSING;
+                }
+            }
+        }
+    }
+
+    result = receiveResponse();
+    if(result == WICONNECT_PROCESSING && !context->nonBlocking)
+    {
+        goto start;
+    }
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult Wiconnect::receiveResponse()
+{
+loop:
+    WiconnectResult result = receivePacket();
+
+    if(result == WICONNECT_PROCESSING)
+    {
+    }
+    else if(result == WICONNECT_SUCCESS)
+    {
+        CommandHeader *header = (CommandHeader*)commandHeaderBuffer;
+        CommandContext *context = (CommandContext*)commandContext;
+
+        // TODO: need to notify safemode
+
+        if(header->response_type == WICONNECT_CMD_TYPE_REPLY || header->response_type == WICONNECT_CMD_TYPE_SAFEMODE)
+        {
+            if(header->response_code != WICONNECT_CMD_SUCCESS)
+            {
+                DEBUG_CMD_ERROR(header->response_code);
+                flush();
+                issueCommandCallback(WICONNECT_CMD_RESPONSE_ERROR);
+                return WICONNECT_CMD_RESPONSE_ERROR;
+            }
+            else if(header->response_len > 0)
+            {
+                DEBUG_CMD_RESPONSE(context->responseBuffer);
+
+                if(header->response_len < (uint16_t)context->responseBufferLen)
+                {
+                    context->responseBuffer[header->response_len] = 0;
+                }
+            }
+            else
+            {
+                *context->responseBuffer = 0;
+            }
+
+            issueCommandCallback(WICONNECT_SUCCESS);
+
+            return WICONNECT_SUCCESS;
+        }
+        else
+        {
+            DEBUG_CMD_LOG(context->responseBuffer);
+            RESET_CMD_HEADER(header);
+            context->responseBufferPtr = context->responseBuffer;
+            goto loop;
+        }
+    }
+    else
+    {
+        issueCommandCallback(result);
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult Wiconnect::receivePacket()
+{
+    CommandHeader *header = (CommandHeader*)commandHeaderBuffer;
+    CommandContext *context = (CommandContext*)commandContext;
+    if(header->bytes_remaining > 0)
+    {
+        uint16_t bytesReceived;
+        static uint8_t buffer[WICONNECT_HEADER_LENGTH];
+
+        while(header->bytes_remaining > 0)
+        {
+            const TimerTimeout timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs);
+            bytesReceived = serial.read((char*)buffer, header->bytes_remaining, timeout);
+            if(bytesReceived == 0)
+            {
+                return timeoutTimer.timedOut(context->timeoutMs) ? WICONNECT_TIMEOUT : WICONNECT_PROCESSING;
+            }
+
+            for(uint8_t *ptr = buffer; bytesReceived > 0; ++ptr)
+            {
+                if(header->response_type == WICONNECT_CMD_TYPE_NULL)
+                {
+                    if( *ptr == WICONNECT_CMD_TYPE_REPLY ||
+                        *ptr == WICONNECT_CMD_TYPE_LOG ||
+                        *ptr == WICONNECT_CMD_TYPE_SAFEMODE)
+                    {
+                        header->response_type = (ResponseType)*ptr;
+                        -- header->bytes_remaining;
+                    }
+                    --bytesReceived;
+                }
+                else if(header->response_code == WICONNECT_CMD_CODE_NULL)
+                {
+                    if(*ptr >= '0' && *ptr <= '7')
+                    {
+                        header->response_code = (ResponseCode)(*ptr - '0' + 1);
+                        --header->bytes_remaining;
+                        header->len_buffer_ptr = header->len_buffer;
+                    }
+                    else
+                    {
+                        RESET_CMD_HEADER(header);
+                    }
+                    --bytesReceived;
+                }
+                else if(header->bytes_remaining > 2)
+                {
+                    uint8_t len_chars = MIN((int)bytesReceived, (int)(header->bytes_remaining-2));
+                    header->bytes_remaining -= len_chars;
+                    bytesReceived -= len_chars;
+                    while(len_chars-- > 0)
+                    {
+                        *header->len_buffer_ptr++ = *ptr++;
+                    }
+                    --ptr; // need to decrement since the for loop increments
+                    if(header->bytes_remaining == 2)
+                    {
+                        uint32_t packetLen;
+                        *header->len_buffer_ptr = 0;
+                        if(!StringUtil::strToUint32((const char*)header->len_buffer, &packetLen))
+                        {
+                            RESET_CMD_HEADER(header);
+                        }
+                        else
+                        {
+                            if(packetLen > 0)
+                            {
+                                if(packetLen <= 2)
+                                {
+                                    return WICONNECT_CMD_RESPONSE_ERROR;
+                                }
+                                packetLen -= 2;
+                            }
+                            if((int)packetLen > context->responseBufferLen)
+                            {
+                                DEBUG_ERROR("Packet larger than response buffer: %d > %d", packetLen, context->responseBufferLen);
+                                return WICONNECT_OVERFLOW;
+                            }
+                            header->response_len = (uint16_t)packetLen;
+                            context->bytesToRead = packetLen;
+                        }
+                    }
+                }
+                else if(header->bytes_remaining == 2)
+                {
+                    --bytesReceived;
+                    if(*ptr == '\r')
+                    {
+                        header->bytes_remaining = 1;
+                    }
+                    else
+                    {
+                        RESET_CMD_HEADER(header);
+                    }
+                }
+                else
+                {
+                    --bytesReceived;
+                    if(*ptr == '\n')
+                    {
+                        header->bytes_remaining = 0;
+                        break;
+                    }
+                    else
+                    {
+                        RESET_CMD_HEADER(header);
+                    }
+                }
+            }
+        }
+    }
+
+    while(context->bytesToRead > 0)
+    {
+        const TimerTimeout timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs);
+        const int bytesToRead = context->bytesToRead;
+        const int bytesReceived = serial.read(context->responseBufferPtr, bytesToRead, timeout);
+        context->responseBufferPtr += bytesReceived;
+        context->bytesToRead -= bytesReceived;
+
+        if(bytesReceived != bytesToRead)
+        {
+            return timeoutTimer.timedOut(context->timeoutMs) ? WICONNECT_TIMEOUT : WICONNECT_PROCESSING;
+        }
+        else if(context->bytesToRead == 0)
+        {
+            char buf[2];
+            int bytesRemaining = 2;
+            *context->responseBufferPtr = 0;
+
+            // read the trailing \r\n
+            while(bytesRemaining > 0)
+            {
+                const int bytesReceived = serial.read(buf, bytesRemaining, 0);
+                bytesRemaining -= bytesReceived;
+
+                if(bytesRemaining > 0 && timeoutTimer.timedOut(context->timeoutMs))
+                {
+                    return WICONNECT_TIMEOUT;
+                }
+            }
+        }
+    }
+
+    return (header->response_code != WICONNECT_CMD_CODE_NULL &&
+            header->response_type != WICONNECT_CMD_TYPE_NULL &&
+            context->bytesToRead == 0) ? WICONNECT_SUCCESS : WICONNECT_PROCESSING;
+}
+
+/*************************************************************************************************/
+void Wiconnect::issueCommandCallback(WiconnectResult result)
+{
+    CommandHeader *header = (CommandHeader*)commandHeaderBuffer;
+    CommandContext *context = (CommandContext*)commandContext;
+#ifdef WICONNECT_ASYNC_TIMER_ENABLED
+    void *returnPtr = (currentQueuedCommand != NULL) ? (void*)currentQueuedCommand : (void*)context->responseBuffer;
+    currentQueuedCommand = NULL;
+    commandProcessorTimer.stop();
+#else
+    void *returnPtr = (void*)context->responseBuffer;
+#endif
+
+    context->callback.call(result, returnPtr, (void*)(uint32_t)header->response_len);
+    commandExecuting = false;
+
+#ifdef WICONNECT_ASYNC_TIMER_ENABLED
+    processNextQueuedCommand();
+#endif
+}
+
+/*************************************************************************************************/
+void Wiconnect::stopCurrentCommand()
+{
+    internalProcessingState = 0;
+    issueCommandCallback(WICONNECT_ABORTED);
+}
+