Test serial console demonstrating various API functions of WiConnect library.

Dependencies:   WiConnect mbed

Files at this revision

API Documentation at this revision

Comitter:
dan_ackme
Date:
Mon Aug 11 11:31:32 2014 +0000
Child:
1:5137ec8f4c45
Commit message:
Initial check-in

Changed in this revision

ConsoleSerial.h Show annotated file Show diff for this revision Revisions of this file
Wiconnect.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
target_config.h Show annotated file Show diff for this revision Revisions of this file
tests/Tests.h Show annotated file Show diff for this revision Revisions of this file
tests/blocking/file/FileCreateTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/file/FileDeleteTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/file/FileListTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/file/FileReadTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/file/FileTests.h Show annotated file Show diff for this revision Revisions of this file
tests/blocking/network/JoinNetworkTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/network/NetworkTests.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/network/NetworkTests.h Show annotated file Show diff for this revision Revisions of this file
tests/blocking/network/ScanNetworkTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/network/WebSetupNetworkTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/socket/HttpGetTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/socket/HttpPostTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/socket/SocketTests.h Show annotated file Show diff for this revision Revisions of this file
tests/blocking/socket/TcpEchoTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/socket/UdpEchoTest.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/wiconnect/WiconnectTests.cpp Show annotated file Show diff for this revision Revisions of this file
tests/blocking/wiconnect/WiconnectTests.h Show annotated file Show diff for this revision Revisions of this file
util/CommandProcessor/CommandProcessor.h Show annotated file Show diff for this revision Revisions of this file
util/CommandProcessor/Console.h Show annotated file Show diff for this revision Revisions of this file
util/log/log.cpp Show annotated file Show diff for this revision Revisions of this file
util/log/log.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ConsoleSerial.h	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdarg.h>
+
+#include "mbed.h"
+
+
+
+
+class ConsoleSerial : public Serial
+{
+public:
+
+    ConsoleSerial(PinName tx, PinName rx) : Serial(tx, rx)
+    {
+
+    }
+
+    void setBaud(int baud)
+    {
+        this->baud(baud);
+    }
+
+    int read()
+    {
+        return getc();
+    }
+
+    void write(int c)
+    {
+        putc(c);
+    }
+
+    void write(const char *s)
+    {
+        puts(s);
+    }
+
+    void write(char *s)
+    {
+        puts(s);
+    }
+
+    void write(const void *data, int size)
+    {
+        Serial::write(data, size);
+    }
+
+    void printf(const char *fmt, ...)
+    {
+        va_list va;
+        va_start(va, fmt);
+        vprintf(fmt, va);
+        va_end(va);
+    }
+
+    void vprintf(const char *fmt, va_list va)
+    {
+        char buf[512];
+        vsnprintf(buf, sizeof(buf), fmt, va);
+        write(buf);
+    }
+
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wiconnect.lib	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/ACKme/code/Wiconnect/#8d91a87ebba2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,102 @@
+/*
+ * 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 "Wiconnect.h"
+#include "util/log/log.h"
+#include "util/CommandProcessor/CommandProcessor.h"
+#include "tests/Tests.h"
+#include "target_config.h"
+
+
+#if TEST_NONBLOCKING_API
+#error 'TEST_NONBLOCKING_API = true' NOT currently supported for the mbed sdk
+#endif
+
+
+int wiconnectLogDebug(const char *str);
+
+
+static const CommandListEntry commandList[] =
+{
+    CMD_HELP_ENTRY,
+    WICONNECT_TEST_CMD_LIST,
+    NETWORK_TEST_CMD_LIST,
+    SOCKET_TEST_CMD_LIST,
+    FILE_TEST_CMD_LIST,
+    CMD_LIST_TERMINATOR
+};
+
+static const SerialConfig serialConfig(WICONNECT_RX_PIN, WICONNECT_TX_PIN, WICONNECT_CTS_PIN, WICONNECT_RTS_PIN, WICONNECT_DEFAULT_BAUD, NULL, WICONNECT_SERIAL_RX_BUFFER_SIZE);
+static Wiconnect wiconnectIfc(serialConfig, NULL, WICONNECT_INTERNAL_BUFFER_SIZE, WICONNECT_RESET_PIN, WICONNECT_WAKE_PIN, TEST_NONBLOCKING_API);
+
+ConsoleSerial consoleSerial(SERIAL_TX, SERIAL_RX);
+CommandProcessor cmdProcessor(&consoleSerial, commandList);
+char testBuffer[TEST_BUFFER_LENGTH];
+
+
+/*************************************************************************************************/
+int main(int argc, char *argv[])
+{
+    WiconnectResult result;
+
+    consoleSerial.setBaud(CONSOLE_BAUD);
+
+#ifdef ENABLE_WICONNECT_DEBUG
+    wiconnectIfc.setDebugLogger(LogFunc(wiconnectLogDebug));
+#endif
+
+    initialize_loop:
+    {
+        LOG_INFO("\r\n\r\nInitializing WiConnect...");
+        if(WICONNECT_FAILED(result, wiconnectIfc.init(true)))
+        {
+            LOG_WICONNECT_ERROR(result, "Failed to initialize Wiconnect");
+            LOG_INFO("Press any key to retry initialization...");
+            int c = consoleSerial.getc();
+            goto initialize_loop;
+        }
+    }
+
+    {
+        char version[WICONNECT_MAX_VERSION_SIZE];
+        if(!WICONNECT_FAILED(result, wiconnectIfc.getVersion(version, WICONNECT_MAX_VERSION_SIZE)))
+        {
+            LOG_INFO("Version: %s", version);
+        }
+    }
+
+    LOG_INFO("WiConnect test app ready...");
+
+    for(;;)
+    {
+        Command cmd;
+        cmdProcessor.waitForCommand(&cmd);
+        if(WICONNECT_FAILED(result, cmd.execute()))
+        {
+            LOG_WICONNECT_ERROR(result, "Failed to execute command");
+            if(result == WICONNECT_CMD_RESPONSE_ERROR)
+            {
+                LOG_ERROR("WiConnect command response code: %s", wiconnectIfc.getLastCommandResponseCodeStr());
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+/*************************************************************************************************/
+int wiconnectLogDebug(const char *str)
+{
+    logDebug(str);
+    return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/6213f644d804
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/target_config.h	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifndef TARGET_SEABASS
+//#define TARGET_NUCLEO_F401RE
+#endif
+
+// The BAUD rate your PC/MAC/Linux terminal uses with the eval board
+#define CONSOLE_BAUD 115200
+
+
+// Uncomment this to enable WiConnect serial interface hardware flow control
+// NOTE: your platform must support the serial flow control api functions
+//#define ENABLE_FLOW_CONTROL
+
+// Uncomment to view debug messages from WiConnect library
+#define ENABLE_WICONNECT_DEBUG
+
+
+#define WICONNECT_INTERNAL_BUFFER_SIZE (4*1024)
+#define WICONNECT_SERIAL_RX_BUFFER_SIZE (4*1024)
+
+#define DEFAULT_CMD_GETCHAR_TIMEOUT 250
+#define DEFAULT_COMMAND_LINE_LENGTH_MAX 128
+#define DEFAULT_COMMAND_MAX_HISTORY 16
+#define DEFAULT_CMD_PROMPT_STR "> "
+#define DEFAULT_COMMAND_MAX_ARGV 16
+
+#define TEST_NONBLOCKING_API false
+#define TEST_BUFFER_LENGTH 4*1024
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Seabass Target Configuration
+#ifdef TARGET_SEABASS
+
+#define WICONNECT_TX_PIN PA_9
+#define WICONNECT_RX_PIN PA_10
+#define WICONNECT_RESET_PIN PB_0
+#define WICONNECT_WAKE_PIN NC
+
+#ifdef ENABLE_FLOW_CONTROL
+#define WICONNECT_CTS_PIN PA_11
+#define WICONNECT_RTS_PIN PA_12
+#else
+#define WICONNECT_CTS_PIN NC
+#define WICONNECT_RTS_PIN NC
+#endif
+
+#endif
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Nucleo F401RE Target Configuration
+#ifdef TARGET_NUCLEO_F401RE
+
+#define WICONNECT_TX_PIN PA_9
+#define WICONNECT_RX_PIN PA_10
+#define WICONNECT_RESET_PIN PB_8
+#define WICONNECT_WAKE_PIN NC
+
+#ifdef ENABLE_FLOW_CONTROL
+#define WICONNECT_CTS_PIN PA_11
+#define WICONNECT_RTS_PIN PA_12
+#else
+#define WICONNECT_CTS_PIN NC
+#define WICONNECT_RTS_PIN NC
+#endif
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/Tests.h	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string.h>
+
+#include "Wiconnect.h"
+#include "util/log/log.h"
+#include "ConsoleSerial.h"
+
+
+#if TEST_NONBLOCKING_API
+//#include "nonblocking/wiconnect/WiconnectTests.h"
+//#include "nonblocking/network/NetworkTests.h"
+//#include "nonblocking/socket/SocketTests.h"
+#else
+#include "blocking/wiconnect/WiconnectTests.h"
+#include "blocking/network/NetworkTests.h"
+#include "blocking/socket/SocketTests.h"
+#include "blocking/file/FileTests.h"
+#endif
+
+
+
+
+#include "StringUtil.h"
+
+#include "target_config.h"
+
+
+extern char testBuffer[TEST_BUFFER_LENGTH];
+
+extern ConsoleSerial consoleSerial;
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/file/FileCreateTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,127 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+typedef struct
+{
+    uint32_t bytesRemaining;
+} fileInfo_t;
+
+
+static WiconnectResult fileReadCallback(void *user, void *data, int maxReadSize, int *bytesRead);
+
+
+
+
+
+/*************************************************************************************************/
+WiconnectResult fileCreateCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+    const char *name;
+    uint32_t size;
+    uint32_t version = 0;
+    uint32_t type = FILE_TYPE_ANY;
+    const int savedTimeOut = wiconnect->getCommandDefaultTimeout();
+    fileInfo_t fileInfo;
+
+
+    if(argc < 2)
+    {
+        LOG_ERROR("must specify file name and size");
+        return WICONNECT_BAD_ARG;
+    }
+
+    name = argv[0];
+    if(!StringUtil::strToUint32(argv[1], &size))
+    {
+        LOG_ERROR("invalid file size");
+        return WICONNECT_BAD_ARG;
+    }
+
+    if(argc > 2)
+    {
+        if(!Wiconnect::fileVersionStrToInt(argv[2], &version))
+        {
+            LOG_ERROR("invalid file version");
+            return WICONNECT_BAD_ARG;
+        }
+    }
+    if(argc > 3)
+    {
+        if(!StringUtil::strHexToUint32(argv[3], &type))
+        {
+            LOG_ERROR("invalid file type");
+            return WICONNECT_BAD_ARG;
+        }
+    }
+
+    fileInfo.bytesRemaining = size;
+    wiconnect->setCommandDefaultTimeout(30000); // increase the timeout so the user can enter data
+
+    if(!WICONNECT_FAILED(result, wiconnect->createFile(ReaderFunc(fileReadCallback), &fileInfo, name, size, version, (FileType)type)))
+    {
+        LOG_INFO("File created");
+    }
+    wiconnect->setCommandDefaultTimeout(savedTimeOut);
+
+    return result;
+}
+
+/*************************************************************************************************/
+static WiconnectResult fileReadCallback(void *user, void *data, int maxReadSize, int *bytesReadPtr)
+{
+    fileInfo_t *info = (fileInfo_t*)user;
+    int bytesToRead = MIN(maxReadSize, info->bytesRemaining);
+
+    if(info->bytesRemaining == 0)
+    {
+        LOG_INFO("All data written");
+        *bytesReadPtr = EOF;
+        return WICONNECT_SUCCESS;
+    }
+
+    LOG_INFO("Enter up to %d bytes (%d bytes remaining,\r\n       Issue $$$ terminate current write):", bytesToRead, info->bytesRemaining);
+
+    uint8_t *ptr = (uint8_t*)data;
+    int bytesRead = 0;
+    int terminateCount = 0;
+
+    while(bytesToRead > 0)
+    {
+        int c = consoleSerial.getc();
+        consoleSerial.putc(c);
+        terminateCount = (c == '$') ? terminateCount+1 : 0;
+        if(terminateCount >= 3)
+        {
+            break;
+        }
+        *ptr++ = (uint8_t)c;
+        ++bytesRead;
+        --bytesToRead;
+    }
+
+    // remove '$$' from data if we terminated
+    if(terminateCount == 3)
+    {
+        bytesRead -= 2;
+    }
+
+    info->bytesRemaining -= bytesRead;
+    *bytesReadPtr = bytesRead;
+    consoleSerial.write("\r\n");
+
+    return WICONNECT_SUCCESS;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/file/FileDeleteTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+
+/*************************************************************************************************/
+WiconnectResult fileDeleteCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+
+    if(argc != 1)
+    {
+        LOG_ERROR("must specify file name to delete");
+        return WICONNECT_BAD_ARG;
+    }
+
+    if(!WICONNECT_FAILED(result, wiconnect->deleteFile(argv[0])))
+    {
+        LOG_INFO("File delete");
+    }
+    return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/file/FileListTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,98 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+
+static void printFileList(const FileList &fileList);
+
+
+
+/*************************************************************************************************/
+WiconnectResult fileListCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+    FileList fileList;
+    uint32_t type = FILE_TYPE_ANY;
+    const char *name = NULL;
+    uint32_t version = 0;
+
+    while(argc > 0)
+    {
+        if(argv[0][0] != '-' || argc < 2)
+        {
+            LOG_ERROR("Invalid command line argument");
+            return WICONNECT_BAD_ARG;
+        }
+
+        switch(argv[0][1])
+        {
+        case 'v': {
+            if(!Wiconnect::fileVersionStrToInt(argv[1], &version))
+            {
+                LOG_ERROR("Invalid file version");
+                return WICONNECT_BAD_ARG;
+            }
+        } break;
+        case 'n':
+            name = argv[1];
+        break;
+        case 't': {
+            if(!StringUtil::strHexToUint32((const char*)argv[1], &type))
+            {
+                LOG_ERROR("Invalid file type");
+                return WICONNECT_BAD_ARG;
+            }
+        } break;
+        default:
+            LOG_ERROR("Unknown command option: %c", argv[0][1]);
+            return WICONNECT_BAD_ARG;
+        }
+
+        argc -= 2;
+        argv += 2;
+    }
+
+
+    if(!WICONNECT_FAILED(result, wiconnect->listFiles(fileList, name, (FileType)type, version)))
+    {
+        printFileList(fileList);
+    }
+
+    return result;
+
+}
+
+/*************************************************************************************************/
+static void printFileList(const FileList &fileList)
+{
+    int i = 1;
+
+    LOG_INFO("File count: %d", fileList.getCount());
+    for(const File *file = fileList.getListHead(); file != NULL; file = file->getNext(), ++i)
+    {
+        LOG_INFO("------------------------\r\n"
+                 "%d: %s\r\n"
+                "\tVersion: %s\r\n"
+                "\tSize: %d\r\n"
+                "\tType: %s\r\n"
+                "\tFlags: %s\r\n",
+                i, file->getName(),
+                file->getVersionStr(),
+                file->getSize(),
+                Wiconnect::fileTypeToStr(file->getType()),
+                Wiconnect::fileFlagsToStr(file->getFlags()));
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/file/FileReadTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,57 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+static WiconnectResult readFile(File &file);
+
+
+
+/*************************************************************************************************/
+WiconnectResult fileReadCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    File file(512);
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+
+    if(argc != 1)
+    {
+        LOG_ERROR("must specify file name to read");
+        return WICONNECT_BAD_ARG;
+    }
+
+
+    if(!WICONNECT_FAILED(result, wiconnect->openFile(file, argv[0])))
+    {
+        readFile(file);
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+static WiconnectResult readFile(File &file)
+{
+    uint8_t *ptr;
+    uint16_t size;
+
+    while(file.read(&ptr, &size) == WICONNECT_SUCCESS)
+    {
+        LOG_INFO("File data: (%d)\r\n", size);
+        logWrite(ptr, size);
+    }
+
+    return WICONNECT_SUCCESS;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/file/FileTests.h	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#define FILE_TEST_CMD_LIST \
+    ADD_HEADER("File commands:"), \
+    ADD_CMD("ls",            fileList,                       "list files (optionally by name, type, version)", \
+                                                             "Usage: ls [-n <name>] [-t <type>] [-v <version>]\n" \
+                                                             "Examples:\n" \
+                                                             "> ls                  // list all files\n" \
+                                                             "> ls -n *.exe         // list all executable files\n" \
+                                                             "> ls -v 1.2           // list all files with version 1.2\n" \
+                                                             "> ls -t FE            // list all miscellaneous files"), \
+    ADD_CMD("create",       fileCreate,                      "create a file", \
+                                                             "Usage: create <name> <size> [<version> [<type>]]\n" \
+                                                             "Example:\n" \
+                                                             "> create my_file.txt 100 4.56 // create file name 'my_file.txt'\n" \
+                                                             "                              // immediately following should be 100 bytes of data"), \
+    ADD_CMD("read",         fileRead,                        "read a file", \
+                                                             "Usage: read <name>\n" \
+                                                             "Example:\n" \
+                                                             "> read my_file.txt "), \
+    ADD_CMD("delete",       fileDelete,                      "delete a file", \
+                                                             "Usage: delete <name>\n" \
+                                                             "Example:\n" \
+                                                             "> delete my_file.txt ")
+
+
+WiconnectResult fileListCommand(int argc, char **argv);
+WiconnectResult fileCreateCommand(int argc, char **argv);
+WiconnectResult fileReadCommand(int argc, char **argv);
+WiconnectResult fileDeleteCommand(int argc, char **argv);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/network/JoinNetworkTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,62 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+
+static void joinCompleteCallback(WiconnectResult result, void *arg1, void *arg2);
+
+
+/*************************************************************************************************/
+WiconnectResult networkJoinCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+
+    const char *ssid = (argc > 0) ? argv[0] : NULL;
+    const char *password = (argc > 1) ? argv[1] : NULL;
+
+    if(!WICONNECT_FAILED(result, wiconnect->join(ssid, password, Callback(joinCompleteCallback))))
+    {
+        LOG_INFO("Joining network");
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult networkLeaveCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+
+    if(!WICONNECT_FAILED(result, wiconnect->leave()))
+    {
+        LOG_INFO("Successfully disconnected from network");
+    }
+    return result;
+}
+
+/*************************************************************************************************/
+static void joinCompleteCallback(WiconnectResult result, void *arg1, void *arg2)
+{
+    if(result == WICONNECT_SUCCESS)
+    {
+        LOG_INFO("Successfully joined network");
+    }
+    else
+    {
+        LOG_WICONNECT_ERROR(result, "Errors occurred while joining network");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/network/NetworkTests.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,103 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+
+/*************************************************************************************************/
+WiconnectResult networkStatsCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+    NetworkStatus status;
+    NetworkSignalStrength signal;
+    uint32_t ip, nm, gw;
+    bool dhcpEnabled;
+
+    if(WICONNECT_FAILED(result, wiconnect->getIpSettings(&ip, &nm, &gw)))
+    {
+        LOG_INFO("Failed to get IP Settings");
+    }
+    else if(WICONNECT_FAILED(result, wiconnect->setDhcpEnabled(&dhcpEnabled)))
+    {
+        LOG_INFO("Failed to get DHCP setting");
+    }
+    else if(WICONNECT_FAILED(result, wiconnect->getNetworkStatus(&status)))
+    {
+        LOG_INFO("Failed to get network status");
+    }
+    else if(WICONNECT_FAILED(result, wiconnect->getSignalStrength(&signal)))
+    {
+        LOG_INFO("Failed to get signal strength");
+    }
+    else
+    {
+        char ipStr[16], gwStr[16], nmStr[16];
+
+        LOG_INFO("\r\n------------------------\r\n"
+                 "IP: %s\r\n"
+                 "Netmask: %s\r\n"
+                 "Gateway: %s\r\n"
+                 "DHCP enabled: %s\r\n"
+                 "Status: %s\r\n"
+                 "Signal: %s\r\n"
+                 "------------------------",
+                 Wiconnect::ipToStr(ip, ipStr),
+                 Wiconnect::ipToStr(nm, nmStr),
+                 Wiconnect::ipToStr(gw, gwStr),
+                 dhcpEnabled ? "true" : "false",
+                 Wiconnect::networkStatusToStr(status),
+                 Wiconnect::signalStrengthToStr(signal));
+
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult networkPingCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+
+    uint32_t pingTimeMs;
+    const char *domain = (argc > 0) ? argv[0] : NULL;
+
+    if(!WICONNECT_FAILED(result, wiconnect->ping(domain, &pingTimeMs)))
+    {
+        LOG_INFO("Ping reply: %dms", pingTimeMs);
+    }
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult networkLookupCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+
+    if(argc != 1)
+    {
+        return WICONNECT_BAD_ARG;
+    }
+
+    uint32_t ipAddress;
+
+    if(!WICONNECT_FAILED(result, wiconnect->lookup(argv[0], &ipAddress)))
+    {
+        IpStrBuffer buffer;
+        LOG_INFO("IP Address: %s", Wiconnect::ipToStr(ipAddress, buffer));
+    }
+    return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/network/NetworkTests.h	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+
+#define NETWORK_TEST_CMD_LIST \
+    ADD_HEADER("Network commands:"), \
+    ADD_CMD("setup",            networkSetupWeb,             "start/stop/check web setup", \
+                                                             "Usage: setup <start/stop/status> [<ssid> [<password>]]\n" \
+                                                             "Examples:\n" \
+                                                             "> setup start MySSID password\n" \
+                                                             "> setup check\n" \
+                                                             "> setup stop"), \
+    ADD_CMD("join",             networkJoin,                 "Join a network", \
+                                                             "Usage: join [<ssid> [<password>]]"), \
+    ADD_CMD("leave",            networkLeave,                "Leave a network", \
+                                                             "Usage: leave"), \
+    ADD_CMD("netstat",          networkStats,                "Get network information", \
+                                                             "Usage: netstat"), \
+    ADD_CMD("scan",             networkScan,                 "Return list of available networks", \
+                                                             "Usage: scan [<channel list>/<all> [<ssid>]]\n" \
+                                                             "Examples:\n" \
+                                                             "> scan 1,6,11\n" \
+                                                             "> scan all \"My Network's Name\""), \
+    ADD_CMD("ping",             networkPing,                 "Ping a network", \
+                                                             "Usage: ping [<host/IP address>]\n" \
+                                                             "Examples:\n" \
+                                                             "> ping    // ping the gateway\n" \
+                                                             "> ping www.ack.me"), \
+    ADD_CMD("lookup",           networkLookup,               "Resolve domain name to IP address", \
+                                                             "Usage: lookup <domain>\n" \
+                                                             "Examples:\n" \
+                                                             "> lookup www.ack.me")
+
+
+WiconnectResult networkSetupWebCommand(int argc, char **argv);
+WiconnectResult networkJoinCommand(int argc, char **argv);
+WiconnectResult networkLeaveCommand(int argc, char **argv);
+WiconnectResult networkStatsCommand(int argc, char **argv);
+WiconnectResult networkScanCommand(int argc, char **argv);
+WiconnectResult networkPingCommand(int argc, char **argv);
+WiconnectResult networkLookupCommand(int argc, char **argv);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/network/ScanNetworkTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,100 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+
+static void printScanResults(const ScanResultList &scanResultList);
+
+
+
+
+/*************************************************************************************************/
+WiconnectResult networkScanCommand(int argc, char **argv)
+{
+    WiconnectResult result = WICONNECT_BAD_ARG;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+    ScanResultList scanResultList;
+    uint8_t channelList[16];
+    const char* ssid = NULL;
+    uint8_t *channelListPtr = NULL;
+
+    if(argc > 0)
+    {
+        if(strcmp(argv[0], "all") != 0)
+        {
+            char *ch_tok;
+            char *chListPtr = argv[0];
+            uint8_t ch_count = 0;
+
+            while((ch_tok = strtok(chListPtr, ","))  != NULL)
+            {
+                intmax_t x;
+
+                if(!StringUtil::parseInt(ch_tok, &x, 1, 14))
+                {
+                    return WICONNECT_BAD_ARG;
+                }
+                channelList[ch_count++] = (uint8_t)x;
+                chListPtr = NULL;
+            }
+            channelList[ch_count] = 0;
+            channelListPtr = channelList;
+        }
+        --argc;
+        ++argv;
+    }
+
+    if(argc > 0)
+    {
+        ssid = argv[0];
+    }
+
+    if(!WICONNECT_FAILED(result, wiconnect->scan(scanResultList, channelListPtr, ssid)))
+    {
+        printScanResults(scanResultList);
+    }
+
+    return result;
+}
+
+
+
+/*************************************************************************************************/
+static void printScanResults(const ScanResultList &scanResultList)
+{
+    SsidStrBuffer ssidBuffer;
+    MacAddressStrBuffer macBuffer;
+    char rateBuffer[16];
+    int i = 1;
+
+    LOG_INFO("Scan result count: %d", scanResultList.getCount());
+    for(const ScanResult *res = scanResultList.getListHead(); res != NULL; res = res->getNext(), ++i)
+    {
+        LOG_INFO("------------------------\r\n"
+                "%d: %s\r\n"
+                 "\tChannel: %d\r\n"
+                 "\tSignal: %s\r\n"
+                 "\tSecurity: %s\r\n"
+                 "\tRate: %s\r\n"
+                 "\tBSSID: %s",
+                 i, Wiconnect::ssidToStr(res->getSsid(), ssidBuffer),
+                 res->getChannel(),
+                 Wiconnect::signalStrengthToStr(res->getSignalStrength()),
+                 Wiconnect::networkSecurityToStr(res->getSecurityType()),
+                 res->getRateStr(rateBuffer),
+                 Wiconnect::macAddressToStr(res->getMacAddress(), macBuffer));
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/network/WebSetupNetworkTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,67 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+static void webSetupCompleteCallback(WiconnectResult result, void *arg1, void *arg2);
+
+
+/*************************************************************************************************/
+WiconnectResult networkSetupWebCommand(int argc, char **argv)
+{
+    WiconnectResult result = WICONNECT_BAD_ARG;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+
+    if(strcmp(argv[0], "status") == 0)
+    {
+        bool isRunning;
+
+        if(!WICONNECT_FAILED(result, wiconnect->isWebSetupRunning(&isRunning)))
+        {
+            LOG_INFO("Web setup is %s", isRunning ? "running" : "stopped");
+        }
+    }
+    else if(strcmp(argv[0], "start") == 0)
+    {
+        const char *ssid = (argc > 1) ? argv[1] : NULL;
+        const char *password = (argc > 2) ? argv[2] : NULL;
+
+        if(!WICONNECT_FAILED(result, wiconnect->startWebSetup(ssid, password, Callback(webSetupCompleteCallback))))
+        {
+            LOG_INFO("Web setup started");
+        }
+    }
+    else if(strcmp(argv[0], "stop") == 0)
+    {
+        if(!WICONNECT_FAILED(result, wiconnect->stopWebSetup()))
+        {
+            LOG_INFO("Web setup stopped");
+        }
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+static void webSetupCompleteCallback(WiconnectResult result, void *arg1, void *arg2)
+{
+    if(result == WICONNECT_SUCCESS)
+    {
+        LOG_INFO("Web setup successfully completed");
+    }
+    else
+    {
+        LOG_WICONNECT_ERROR(result, "Web setup finished with errors");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/socket/HttpGetTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,133 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+
+static WiconnectResult addHeadersPrompt(Wiconnect *wiconnect, Socket &socket);
+static WiconnectResult readResponse(Socket &socket);
+
+
+
+/*************************************************************************************************/
+WiconnectResult socketHttpGetCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+    Socket socket(sizeof(testBuffer), testBuffer);
+    const char *url;
+    bool addHeaders = false;
+
+    if(argc < 1)
+    {
+        LOG_ERROR("must specify url");
+        return WICONNECT_BAD_ARG;
+    }
+    url = argv[0];
+
+    if(argc > 1)
+    {
+        addHeaders = true;
+    }
+
+
+    if(!WICONNECT_FAILED(result, wiconnect->httpGet(socket, url, addHeaders)))
+    {
+        uint32_t status;
+        if(addHeaders)
+        {
+            if(WICONNECT_FAILED(result, addHeadersPrompt(wiconnect, socket)))
+            {
+                goto exit;
+            }
+            else if(WICONNECT_FAILED(result, wiconnect->httpGetStatus(socket, &status)))
+            {
+                goto exit;
+            }
+            LOG_INFO("HTTP Status: %d", status);
+        }
+
+        result = readResponse(socket);
+    }
+
+exit:
+    return result;
+}
+
+
+
+
+/*************************************************************************************************/
+static WiconnectResult addHeadersPrompt(Wiconnect *wiconnect, Socket &socket)
+{
+    WiconnectResult result;
+
+    char buffer[128];
+    for(;;)
+    {
+        LOG_INFO("Enter header 'key,value\\n' (or 'done\\n' to issue request):");
+        char *ptr = buffer;
+
+        for(;;)
+        {
+            int c = consoleSerial.getc();
+            consoleSerial.putc(c);
+            if(c == '\r')
+                continue;
+            if(c == '\n')
+            {
+                *ptr = 0;
+                break;
+            }
+            *ptr++ = (char)c;
+        }
+
+        if(strcmp(buffer, "done") == 0)
+        {
+            return WICONNECT_SUCCESS;
+        }
+
+        char *value = strchr(buffer, ',');
+        if(value == NULL)
+        {
+            LOG_ERROR("Mal-formed key,value pair. Must be: <key>,<value>");
+            continue;
+        }
+
+        *value++ = 0;
+
+        if(WICONNECT_FAILED(result, wiconnect->httpAddHeader(socket, buffer, value)))
+        {
+            LOG_ERROR("Failed to add header key, value");
+            break;
+        }
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+static WiconnectResult readResponse(Socket &socket)
+{
+    uint8_t c;
+
+    LOG_INFO("Response data:");
+    while(socket.getc(&c) == WICONNECT_SUCCESS) // NOTE: getc() is extremely inefficient here,
+                                                //       is only used to test its functionality
+    {
+        logWrite(&c, 1);
+    }
+
+    return WICONNECT_SUCCESS;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/socket/HttpPostTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,94 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+#define TEST_SERVER_URL "http://www.posttestserver.com"
+#define CONTEXT_TYPE "text/plain"
+
+
+static WiconnectResult addPostData(Socket &socket);
+static WiconnectResult readResponse(Socket &socket);
+
+
+/*************************************************************************************************/
+WiconnectResult socketHttpPostCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+    Socket socket(0, NULL, sizeof(testBuffer), testBuffer);
+    uint32_t status;
+
+    if(WICONNECT_FAILED(result, wiconnect->httpPost(socket, TEST_SERVER_URL, CONTEXT_TYPE)))
+    {
+        LOG_ERROR("Failed to open POST connection");
+    }
+    else if(WICONNECT_FAILED(result, addPostData(socket)))
+    {
+        LOG_ERROR("Failed to add POST data");
+    }
+    else if(WICONNECT_FAILED(result, wiconnect->httpGetStatus(socket, &status)))
+    {
+        LOG_ERROR("Failed to read HTTP status");
+    }
+    else if(WICONNECT_FAILED(result, readResponse(socket)))
+    {
+        LOG_ERROR("Failed to read POST response");
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+static WiconnectResult addPostData(Socket &socket)
+{
+    WiconnectResult result;
+
+    LOG_INFO("Enter post data ('\\n' issues request):");
+
+    int c;
+
+    for(;;)
+    {
+        c = consoleSerial.getc();
+        consoleSerial.putc(c);
+        if(c == '\r')
+            continue;
+        if(c == '\n')
+            break;
+
+        if(WICONNECT_FAILED(result, socket.putc(c)))
+        {
+            return result;
+        }
+    }
+
+    return socket.flushTxBuffer();
+}
+
+/*************************************************************************************************/
+static WiconnectResult readResponse(Socket &socket)
+{
+    uint8_t *buffer;
+    uint16_t size;
+
+    LOG_INFO("Response data:");
+
+    while(socket.read(&buffer, &size) == WICONNECT_SUCCESS)
+    {
+        logWrite(buffer, size);
+    }
+
+    return WICONNECT_SUCCESS;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/socket/SocketTests.h	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+
+#define SOCKET_TEST_CMD_LIST \
+    ADD_HEADER("Socket commands:"), \
+    ADD_CMD("get",               socketHttpGet,           "Issue HTTP GET request with optional headers", \
+                                                          "Usage: get <url> [true]\n" \
+                                                          "Examples:\n" \
+                                                          "> get ack.me // immediately issue GET and print page\n" \
+                                                          "> get ack.me true // issue GET then add HTTP headers\n"), \
+    ADD_CMD("post",              socketHttpPost,          "Issue HTTP POST request to http://www.posttestserver.com/", \
+                                                          "Usage: post\n" \
+                                                          "Examples:\n" \
+                                                          "> post // opens POST connection then enter the post data"), \
+    ADD_CMD("tcp",               socketTcpClientEcho,     "Open TCP connection, transmit data and receivd echoed data", \
+                                                          "Usage: tcp <host> <port> [<packets count> [<delay> <size>]]]"), \
+    ADD_CMD("udp",               socketUdpClientEcho,     "Open UDP connection, transmit data and receivd echoed data", \
+                                                          "Usage: udp <host> <port> [<packets count> [<delay> <size>]]]")
+
+
+
+WiconnectResult socketTcpClientEchoCommand(int argc, char **argv);
+WiconnectResult socketUdpClientEchoCommand(int argc, char **argv);
+WiconnectResult socketHttpGetCommand(int argc, char **argv);
+WiconnectResult socketHttpPostCommand(int argc, char **argv);
+WiconnectResult socketHttpHeadCommand(int argc, char **argv);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/socket/TcpEchoTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,152 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+
+static WiconnectResult processData(Socket &socket, uint32_t count, uint32_t delay, uint32_t size);
+
+
+
+/*************************************************************************************************/
+WiconnectResult socketTcpClientEchoCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+    Socket socket(sizeof(testBuffer)/2, testBuffer, sizeof(testBuffer)/2, testBuffer + sizeof(testBuffer)/2);
+    const char *host;
+    uint32_t port;
+    uint32_t delay = 5;
+    uint32_t count = 1000;
+    uint32_t size = 256;
+
+    if(argc < 2)
+    {
+        LOG_ERROR("Must specify host and port");
+        return WICONNECT_BAD_ARG;
+    }
+    host = argv[0];
+
+    if(!StringUtil::strToUint32((const char*)argv[1], &port))
+    {
+        LOG_ERROR("Invalid port");
+        return WICONNECT_BAD_ARG;
+    }
+    if(argc > 2 && !StringUtil::strToUint32((const char*)argv[2], &count))
+    {
+        LOG_ERROR("Invalid packet count");
+        return WICONNECT_BAD_ARG;
+    }
+    if(argc > 3 && !StringUtil::strToUint32((const char*)argv[3], &delay))
+    {
+        LOG_ERROR("Invalid packet delay");
+        return WICONNECT_BAD_ARG;
+    }
+    if(argc > 4 && (!StringUtil::strToUint32((const char*)argv[4], &size) || size > sizeof(testBuffer)/2))
+    {
+        LOG_ERROR("Invalid packet size");
+        return WICONNECT_BAD_ARG;
+    }
+
+    if(WICONNECT_FAILED(result, wiconnect->tcpConnect(socket, host, port)))
+    {
+        LOG_ERROR("Failed to connect to server");
+    }
+    else
+    {
+        result = processData(socket, count, delay, size);
+    }
+
+    return result;
+}
+
+
+/*************************************************************************************************/
+static WiconnectResult processData(Socket &socket, uint32_t count, uint32_t delay, uint32_t size)
+{
+    WiconnectResult result;
+    uint8_t *txBuffer = socket.getTxBuffer();
+    const int txBufferLen = socket.getTxBufferSize();
+    uint8_t writeCounter = 32;
+    uint8_t readCounter = 32;
+    uint32_t bytesSent = 0;
+    uint32_t bytesReceived = 0;
+
+    LOG_INFO("\r\n------------------\r\n"
+             "Starting TCP Echo Test:\r\n"
+            "Packet count: %d\r\n"
+            "Packet size: %d\r\n"
+            "Packet delay: %d\r\n"
+            "(Press any key to terminate)",
+            count, size, delay);
+
+    for(int i = 0; i < count || bytesReceived < bytesSent; ++i)
+    {
+        if(i < count)
+        {
+            uint8_t *ptr = txBuffer;
+            int l = size;
+            while(l--)
+            {
+                *ptr++ = writeCounter++;
+                if(writeCounter == 128)
+                    writeCounter = 32;
+            }
+
+            if(WICONNECT_FAILED(result, socket.write(size)))
+            {
+                break;
+            }
+            bytesSent += size;
+            consoleSerial.putc('.');
+        }
+
+        if(consoleSerial.readable())
+        {
+            int c = consoleSerial.getc();
+            break;
+        }
+
+        delayMs(delay);
+
+        uint8_t *readPtr;
+        uint16_t readLen;
+        if(WICONNECT_FAILED(result, socket.read(&readPtr, &readLen)))
+        {
+            break;
+        }
+        bytesReceived += readLen;
+
+        while(readLen--)
+        {
+            if(*readPtr != readCounter)
+            {
+                LOG_ERROR("Invalid: %02X != %02X", *readPtr, readCounter);
+            }
+            ++readPtr;
+            ++readCounter;
+            if(readCounter == 128)
+                readCounter = 32;
+        }
+    }
+
+    consoleSerial.write("\r\n");
+    LOG_INFO("------------------\r\n"
+             "TCP Echo Test Complete:\r\n"
+            "Bytes sent: %d\r\n"
+            "Bytes received: %d\r\n",
+            bytesSent, bytesReceived);
+
+    return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/socket/UdpEchoTest.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,153 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+
+
+static WiconnectResult processData(Socket &socket, uint32_t count, uint32_t delay, uint32_t size);
+
+
+
+/*************************************************************************************************/
+WiconnectResult socketUdpClientEchoCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+    Socket socket(sizeof(testBuffer)/2, testBuffer, sizeof(testBuffer)/2, testBuffer + sizeof(testBuffer)/2);
+    const char *host;
+    uint32_t port;
+    uint32_t delay = 5;
+    uint32_t count = 1000;
+    uint32_t size = 256;
+
+    if(argc < 2)
+    {
+        LOG_ERROR("Must specify host and port");
+        return WICONNECT_BAD_ARG;
+    }
+    host = argv[0];
+
+    if(!StringUtil::strToUint32((const char*)argv[1], &port))
+    {
+        LOG_ERROR("Invalid port");
+        return WICONNECT_BAD_ARG;
+    }
+    if(argc > 2 && !StringUtil::strToUint32((const char*)argv[2], &count))
+    {
+        LOG_ERROR("Invalid packet count");
+        return WICONNECT_BAD_ARG;
+    }
+    if(argc > 3 && !StringUtil::strToUint32((const char*)argv[3], &delay))
+    {
+        LOG_ERROR("Invalid packet delay");
+        return WICONNECT_BAD_ARG;
+    }
+    if(argc > 4 && (!StringUtil::strToUint32((const char*)argv[4], &size) || size > sizeof(testBuffer)/2))
+    {
+        LOG_ERROR("Invalid packet size");
+        return WICONNECT_BAD_ARG;
+    }
+
+    if(WICONNECT_FAILED(result, wiconnect->udpConnect(socket, host, port)))
+    {
+        LOG_ERROR("Failed to connect to server");
+    }
+    else
+    {
+        result = processData(socket, count, delay, size);
+    }
+
+    return result;
+}
+
+
+/*************************************************************************************************/
+static WiconnectResult processData(Socket &socket, uint32_t count, uint32_t delay, uint32_t size)
+{
+    WiconnectResult result;
+    uint8_t *txBuffer = socket.getTxBuffer();
+    const int txBufferLen = socket.getTxBufferSize();
+    uint8_t writeCounter = 32;
+    uint8_t readCounter = 32;
+    uint32_t bytesSent = 0;
+    uint32_t bytesReceived = 0;
+
+    LOG_INFO("\r\n------------------\r\n"
+             "Starting UDP Echo Test:\r\n"
+            "Packet count: %d\r\n"
+            "Packet size: %d\r\n"
+            "Packet delay: %d\r\n"
+            "(Press any key to terminate)",
+            count, size, delay);
+
+    for(int i = 0; i < count || bytesReceived < bytesSent; ++i)
+    {
+        if(i < count)
+        {
+            uint8_t *ptr = txBuffer;
+            int l = size;
+            while(l--)
+            {
+                *ptr++ = writeCounter++;
+                if(writeCounter == 128)
+                    writeCounter = 32;
+            }
+
+            if(WICONNECT_FAILED(result, socket.write(size)))
+            {
+                break;
+            }
+            bytesSent += size;
+            consoleSerial.putc('.');
+        }
+
+        if(consoleSerial.readable())
+        {
+            int c = consoleSerial.getc();
+            break;
+        }
+
+        delayMs(delay);
+
+        uint8_t *readPtr;
+        uint16_t readLen;
+        if(WICONNECT_FAILED(result, socket.read(&readPtr, &readLen)))
+        {
+            break;
+        }
+        bytesReceived += readLen;
+
+        while(readLen--)
+        {
+            if(*readPtr != readCounter)
+            {
+                LOG_ERROR("Invalid: %02X != %02X", *readPtr, readCounter);
+            }
+            ++readPtr;
+            ++readCounter;
+            if(readCounter == 128)
+                readCounter = 32;
+        }
+    }
+
+    consoleSerial.write("\r\n");
+    LOG_INFO("------------------\r\n"
+             "UDP Echo Test Complete:\r\n"
+            "Bytes sent: %d\r\n"
+            "Bytes received: %d\r\n",
+            bytesSent, bytesReceived);
+
+    return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/wiconnect/WiconnectTests.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,137 @@
+/*
+ * 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 "tests/Tests.h"
+#include "Wiconnect.h"
+
+
+#define TIMEOUT 10000 // ms
+
+
+static volatile bool wiconnectNonBlockingCommandFinished = false;
+
+
+
+/*************************************************************************************************/
+WiconnectResult wiconnectSendRawBlockingCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+
+    strcpy(testBuffer, argv[0]);
+    --argc;
+    ++argv;
+
+    while(argc--)
+    {
+        strcat(testBuffer, " ");
+        strcat(testBuffer, argv[0]);
+        ++argv;
+    }
+
+    if(!WICONNECT_FAILED(result,  wiconnect->sendCommand(TIMEOUT, testBuffer, TEST_BUFFER_LENGTH, testBuffer)))
+    {
+        LOG_INFO_WRITE_STR("Response:\r\n", wiconnect->getResponseBuffer());
+    }
+
+    return result;
+}
+
+
+
+/*************************************************************************************************/
+static void responseHandler(WiconnectResult result, void *response, void *responseLen)
+{
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+
+    wiconnectNonBlockingCommandFinished = true;
+
+    if(result == WICONNECT_SUCCESS)
+    {
+        LOG_INFO_WRITE_STR("Non-blocking Response:\r\n", (const char*)response);
+    }
+    else
+    {
+        LOG_WICONNECT_ERROR(result, "Non-blocking command failed");
+    }
+}
+
+/*************************************************************************************************/
+WiconnectResult wiconnectSendRawNonBlockingCommand(int argc, char **argv)
+{
+
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+    char *ptr = testBuffer;
+
+    strcpy(testBuffer, argv[0]);
+    --argc;
+    ++argv;
+
+    while(argc--)
+    {
+        strcat(testBuffer, " ");
+        strcat(testBuffer, argv[0]);
+        ++argv;
+    }
+
+    wiconnectNonBlockingCommandFinished = false;
+    if(WICONNECT_FAILED(result,  wiconnect->sendCommand(Callback(responseHandler), testBuffer, TEST_BUFFER_LENGTH, TIMEOUT, testBuffer)))
+    {
+    }
+    else if(!wiconnectNonBlockingCommandFinished)
+    {
+        LOG_INFO("Non-blocking command processing...");
+    }
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult wiconnectGetVersionCommand(int argc, char **argv)
+{
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+
+    if(!WICONNECT_FAILED(result, wiconnect->getVersion(testBuffer, sizeof(testBuffer))))
+    {
+        LOG_INFO("Version: %s", testBuffer);
+    }
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult wiconnectDebugEnableCommand(int argc, char **argv)
+{
+    extern int wiconnectLogDebug(const char *str);
+    WiconnectResult result;
+    Wiconnect *wiconnect = Wiconnect::getInstance();
+    bool enabled;
+
+    if(!StringUtil::parseBool(argv[0], &enabled))
+    {
+        return WICONNECT_BAD_ARG;
+    }
+
+    if(enabled)
+    {
+        wiconnect->setDebugLogger(LogFunc(wiconnectLogDebug));
+        LOG_INFO("WiConnet debugging enabled");
+    }
+    else
+    {
+        wiconnect->setDebugLogger(LogFunc());
+        LOG_INFO("WiConnet debugging disabled");
+    }
+
+    return WICONNECT_SUCCESS;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/blocking/wiconnect/WiconnectTests.h	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+
+#define WICONNECT_TEST_CMD_LIST \
+    ADD_HEADER("WiConnect commands:"), \
+    ADD_CMD(":",            wiconnectSendRawBlocking,           "Send a blocking raw wiconnect command to module", \
+                                                                "Usage: : <wiconnet command> [command options]\n" \
+                                                                "Example:\n> : get network.status"), \
+    ADD_CMD("#",            wiconnectSendRawNonBlocking,        "Send a non-blocking raw wiconnect command to module", \
+                                                                "Usage: # <wiconnet command> [command options]\n" \
+                                                                "Example:\n> # get network.status"), \
+    ADD_CMD("ver",          wiconnectGetVersion,                "Get WiConnect version string",  \
+                                                                "Usage: ver"), \
+    ADD_CMD("debug",        wiconnectDebugEnable,               "Enabled/disable wiconnect library debug messages", \
+                                                                "Usage: debug <on/off>")
+
+
+
+
+WiconnectResult wiconnectSendRawBlockingCommand(int argc, char **argv);
+WiconnectResult wiconnectSendRawNonBlockingCommand(int argc, char **argv);
+WiconnectResult wiconnectGetVersionCommand(int argc, char **argv);
+WiconnectResult wiconnectDebugEnableCommand(int argc, char **argv);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/CommandProcessor/CommandProcessor.h	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <ctype.h>
+
+#include "Wiconnect.h"
+#include "Console.h"
+#include "StringUtil.h"
+#include "util/log/log.h"
+
+
+
+#define ADD_HEADER(header) { header, NULL, NULL, NULL}
+#define ADD_CMD(key, func, desc, ext) { key, func ## Command, desc, ext }
+#define CMD_LIST_TERMINATOR { NULL, NULL, NULL, NULL }
+#define CMD_HELP_ENTRY { "?", NULL, "Print list of commands. Add '-v' option to print verbosely", NULL }, \
+                       { "help", NULL, "Print list of commands. Add '-v' option to print verbosely", NULL }
+
+typedef WiconnectResult (*CommandProcessorFunc)(int, char**);
+
+typedef struct
+{
+    const char *key;
+    CommandProcessorFunc func;
+    const char *desc;
+    const char *extendedDesc;
+} CommandListEntry;
+
+
+/*************************************************************************************************/
+class Command
+{
+public:
+    Command()
+    {
+        argc = -1;
+        func = NULL;
+    }
+
+    void init(int argc_, CommandProcessorFunc func_)
+    {
+        argc = argc_;
+        func = func_;
+    }
+
+    char** getArgvBuffer()
+    {
+        return argv;
+    }
+
+    WiconnectResult execute()
+    {
+        return func(argc, argv);
+    }
+
+private:
+    int argc;
+    char *argv[DEFAULT_COMMAND_MAX_ARGV];
+    CommandProcessorFunc func;
+};
+
+
+
+/*************************************************************************************************/
+class CommandProcessor
+{
+private:
+    const CommandListEntry *commandList;
+    Console console;
+    ConsoleSerial *serial;
+    int commandListSize;
+
+public:
+    /*************************************************************************************************/
+    CommandProcessor(ConsoleSerial *serial_, const CommandListEntry *commandList_) :
+        commandList(commandList_), console(serial_), serial(serial_), commandListSize(0)
+    {
+        for(const CommandListEntry *cmd = commandList; cmd->key != NULL; ++cmd)
+        {
+            ++commandListSize;
+        }
+    }
+
+    /*************************************************************************************************/
+    ~CommandProcessor()
+    {
+    }
+
+    /*************************************************************************************************/
+    void waitForCommand(Command *cmdPtr)
+    {
+        for(;;)
+        {
+            char *line;
+            char **argv;
+            intmax_t index;
+            int lineLength;
+            const CommandListEntry *foundCmd = NULL;
+
+            console.readLine(&line, &lineLength);
+
+            if(lineLength == 0)
+            {
+                continue;
+            }
+
+            argv = cmdPtr->getArgvBuffer();
+            int argc = parseArgs(line, DEFAULT_COMMAND_MAX_ARGV, argv);
+            if(argc == -1)
+            {
+                LOG_ERROR("Failed to parse commandline");
+                continue;
+            }
+
+            if(argv[0][0] == '?' || strcmp(argv[0], "help") == 0)
+            {
+                bool verbose = (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'v');
+                printHelp(verbose);
+                continue;
+            }
+
+            for(const CommandListEntry *cmd = commandList; cmd->key != NULL; ++cmd)
+            {
+                if(cmd->desc != NULL && strcmp(cmd->key, argv[0]) == 0)
+                {
+                    foundCmd = cmd;
+                    break;
+                }
+            }
+
+            if(foundCmd == NULL)
+            {
+                if(StringUtil::parseInt(argv[0], &index, 0, commandListSize))
+                {
+                    foundCmd = &commandList[(int)index];
+                }
+                else
+                {
+                    LOG_ERROR("Unknown command. Enter: 'help' to list available commands");
+                    continue;
+                }
+            }
+
+            --argc;
+            memmove(argv, &argv[1], sizeof(char*)*argc);
+
+            if(argc == 1 && (argv[0][0] == '?' || (strstr(argv[0], "help") != NULL)))
+            {
+                printCommandHelp(foundCmd, true, -1);
+                continue;
+            }
+            else
+            {
+                cmdPtr->init(argc, foundCmd->func);
+            }
+            break;
+        }
+    }
+
+protected:
+
+    /*************************************************************************************************/
+    void printHelp(bool verbose)
+    {
+        int i = 0;
+        for(const CommandListEntry *cmd = commandList; cmd->key != NULL; ++cmd, ++i)
+        {
+            if(cmd->desc == NULL)
+            {
+                --i;
+                serial->printf("\r\n--------------------------------\r\n"
+                        "%s\r\n", cmd->key);
+                continue;
+            }
+            printCommandHelp(cmd, verbose, i);
+        }
+    }
+
+
+    /*************************************************************************************************/
+    void printCommandHelp(const CommandListEntry *cmd, bool verbose, int i)
+    {
+        if(i != -1)
+            serial->printf("%2d: %10s : %s\r\n", i, cmd->key, cmd->desc);
+        else
+            serial->printf("    %10s : %s\r\n", cmd->key, cmd->desc);
+
+        if(verbose)
+        {
+            if(cmd->extendedDesc != NULL)
+            {
+                const char *newline, *ptr = cmd->extendedDesc;
+
+                print_extended_help:
+                paddHelpSpaces();
+                newline = strchr(ptr, '\n');
+                if(newline == NULL)
+                {
+                    puts(ptr);
+                    return;
+                }
+                else
+                {
+                    while(ptr < newline)
+                        serial->write(*ptr++);
+                    serial->write('\r');
+                    serial->write('\n');
+                    ++ptr;
+                    goto print_extended_help;
+                }
+            }
+        }
+    }
+
+    /*************************************************************************************************/
+    void paddHelpSpaces()
+    {
+        int spaces = 17;
+        while(spaces--)
+            serial->write(' ');
+    }
+
+
+    /*************************************************************************************************/
+    int parseArgs(char *line, int max_argc, char **argv)
+    {
+        // TODO: \x00 style escaping
+        char *p;
+        unsigned char c;
+        int argc = 0;
+        char *tokenstart = NULL;
+        enum states
+        {
+            INITIAL,
+            WORD,
+            STRING
+        } state = INITIAL;
+
+        for (p = line; *p != '\0'; p++)
+        {
+            c = (unsigned char) * p;
+            /* One less because word at end-of-line case increments again */
+            if (argc >= max_argc - 1)
+            {
+                return argc;
+            }
+            switch (state)
+            {
+            case INITIAL:
+                if (isspace(c))
+                {
+                    continue;
+                }
+                if (c == '"')
+                {
+                    state = STRING;
+                    tokenstart = p + 1;
+                    continue;
+                }
+                tokenstart = p;
+                state = WORD;
+                continue;
+            case STRING:
+                if (c == '"')
+                {
+                    state = INITIAL;
+                    *p = 0;
+                    argv[argc++] = tokenstart;
+                }
+                continue;
+            case WORD:
+                if (c == '"')
+                {
+                    state = STRING;
+                    *p = 0;
+                    argv[argc++] = tokenstart;
+                    tokenstart = p + 1;
+                }
+                else if (isspace(c))
+                {
+                    state = INITIAL;
+                    *p = 0;
+                    argv[argc++] = tokenstart;
+                }
+                continue;
+            }
+        }
+        if (state == WORD)
+        {
+            *p = 0;
+            argv[argc++] = tokenstart;
+            argv[argc] = NULL;
+        }
+        else if (state == STRING)
+        {
+            argc = -1; /* Unterminated string */
+        }
+        else
+        {
+            argv[argc] = NULL;
+        }
+
+        return argc;
+    }
+
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/CommandProcessor/Console.h	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,450 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string.h>
+
+#include "ConsoleSerial.h"
+#include "target_config.h"
+
+
+typedef struct
+{
+    int index;
+    int count;
+    const char **choices;
+    char cmd_buffer[32];
+    char *cmd_buffer_ptr;
+    char cmp_offset;
+} console_tab_info_t;
+
+typedef struct context
+{
+    char line[DEFAULT_COMMAND_LINE_LENGTH_MAX];
+    int line_length;
+    //int max_line_length;
+    volatile int cursor_position;
+    char history[DEFAULT_COMMAND_MAX_HISTORY][DEFAULT_COMMAND_LINE_LENGTH_MAX];
+    int history_count;
+    int history_index;
+    //int hisory_length;
+    char CR_char;
+    console_tab_info_t tab_info;
+} console_context_t;
+
+
+class Console
+{
+private:
+    ConsoleSerial *serial;
+    console_context_t context;
+public:
+
+    /*************************************************************************************************/
+    Console(ConsoleSerial *serial_) : serial(serial_)
+    {
+        memset((void*)&context, 0, sizeof(console_context_t));
+    }
+
+    /*************************************************************************************************/
+    ~Console()
+    {
+    }
+
+    /*************************************************************************************************/
+    int readLine(char **line, int *lineLength)
+    {
+        bool in_escape_sequence = false;
+        context.line[0] = 0;
+        context.line_length = 0;
+        context.cursor_position = 0;
+        context.history_index = -1;
+
+        serial->write(DEFAULT_CMD_PROMPT_STR);
+
+        while(context.cursor_position < (DEFAULT_COMMAND_LINE_LENGTH_MAX-1))
+        {
+            int c;
+
+            c = serial->read();
+            if(c == -1)
+            {
+                continue;
+            }
+
+            if(c == '\r' || c == '\n')
+            {
+                context.CR_char = c;
+            }
+
+            if(in_escape_sequence)
+            {
+                in_escape_sequence = process_escape_sequence(c, true);
+            }
+            else
+            {
+                switch((unsigned char)c)
+                {
+                case '\t' : // tab
+                    //process_tab();
+                    break;
+                case '\r': // newline
+                case '\n': // linefeed
+                    if(context.CR_char == c)
+                    {
+                        if(c == '\r')
+                        {
+                            // retrieve \n as well
+                            serial->read();
+                        }
+                        serial->write('\r');
+                        serial->write('\n');;
+                        goto console_readline_finish;
+                    }
+                    break;
+                case 27: // escape character
+                case 0xE0:
+                    in_escape_sequence = true;
+                    break;
+                case '\b':  // backspace
+                case '\x7F':// delete
+                    do_backspace(true);
+                    break;
+                default: {
+                    if((c >= 32) && (c < 127))
+                    {
+                        add_char(c, true);
+                    }
+                } break;
+                }
+                *lineLength = context.line_length;
+            }
+
+//            if(c != '\t')
+//            {
+//                clear_tab_choices();
+//            }
+
+        }
+
+        return -1;
+
+        console_readline_finish:
+        {
+            *line = context.line;
+            *lineLength = context.line_length;
+
+            if(context.line_length > 0)
+            {
+                update_history(context.line);
+            }
+        }
+
+        return 0;
+    }
+
+protected:
+
+    /*************************************************************************************************/
+    bool process_escape_sequence(char c, bool echo)
+    {
+        char previous_char;
+        bool still_in_esc_seq = false;
+
+    #ifdef __WIN32__
+    #define UP_ARROW 'H'
+    //#define RIGHT_ARROW 'M'
+    #define DOWN_ARROW 'P'
+    //#define LEFT_ARROW 'K'
+    //#define HOME 'G'
+    //#define END 'O'
+    #else
+    #define UP_ARROW 'A'
+    #define RIGHT_ARROW 'C'
+    #define DOWN_ARROW 'B'
+    #define LEFT_ARROW 'D'
+    #define HOME 'H'
+    #define END 'F'
+    #endif
+
+        switch((unsigned char)c)
+        {
+    #ifndef __WIN32__
+        case 'O':
+    #endif
+        case ';':
+        case '[':
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+        case 0xE0:
+            still_in_esc_seq = true;
+            break;
+        case UP_ARROW: /* up arrow */
+            cycle_history(false);
+            break;
+        case DOWN_ARROW: /* down arrow */
+            cycle_history(true);
+            break;
+    #ifdef RIGHT_ARROW
+        case RIGHT_ARROW: /* right arrow */
+            update_cursor_position(true);
+            break;
+    #endif
+    #ifdef LEFT_ARROW
+        case LEFT_ARROW: /* left arrow */
+            update_cursor_position(false);
+            break;
+    #endif
+    #ifdef END
+        case END: /* end */
+            move_cursor_position(true);
+            break;
+    #endif
+    #ifdef HOME
+        case HOME: /* home */
+            move_cursor_position(false);
+            break;
+    #endif
+        case '~':  {/* vt320 style control codes */
+            switch(previous_char)
+            {
+            case '1': /* home */
+                move_cursor_position(false);
+                break;
+            case '4': /* end */
+                move_cursor_position(true);
+                break;
+            default:
+                break;
+            }
+        } break;
+        default:
+            break;
+        }
+
+        previous_char = c;
+
+        return still_in_esc_seq;
+    }
+
+    /*************************************************************************************************/
+    void update_history(char *line)
+    {
+        int copy_start_index = DEFAULT_COMMAND_MAX_HISTORY - 2;
+
+        for(int i = 0; i < context.history_count; ++i)
+        {
+            if(strcmp(context.history[i], line) == 0)
+            {
+                copy_start_index = i - 1;
+                break;
+            }
+        }
+
+        if(context.history_count < DEFAULT_COMMAND_MAX_HISTORY)
+        {
+            ++context.history_count;
+        }
+
+        for(int j = copy_start_index; j >= 0; --j)
+        {
+            strcpy(context.history[j+1], context.history[j]);
+        }
+        strcpy(context.history[0], line);
+    }
+
+    /*************************************************************************************************/
+    void cycle_history(bool cycle_down)
+    {
+        if(cycle_down)
+        {
+            --context.history_index;
+
+            if(context.history_index <= -1)
+            {
+                context.history_index = -1;
+                clear_line();
+                return;
+            }
+        }
+        else
+        {
+            if(context.history_index == context.history_count-1)
+            {
+                return;
+            }
+            else
+            {
+                ++context.history_index;
+            }
+        }
+
+        const char *line = context.history[context.history_index];
+
+        clear_line();
+        add_string(line);
+    }
+
+    /*************************************************************************************************/
+    void do_backspace( bool echo )
+    {
+        if ( context.cursor_position > 0 )
+        {
+            --context.cursor_position;
+            if(echo)
+            {
+                serial->write('\b');
+            }
+            remove_char(echo);
+        }
+    }
+
+    /*************************************************************************************************/
+    void add_string(const char *s)
+    {
+        while(*s != 0)
+        {
+            add_char(*s++, true);
+        }
+    }
+
+    /*************************************************************************************************/
+    void add_char(char c, bool echo)
+    {
+        /* move the end of the line out to make space */
+        for (int i = context.line_length + 1; i > context.cursor_position; --i )
+        {
+            context.line[i] = context.line[i - 1];
+        }
+
+        /* insert the character */
+        ++context.line_length;
+        context.line[context.cursor_position] = c;
+
+        if(echo)
+        {
+            /* print out the modified part of the ConsoleBuffer */
+            serial->write(&context.line[context.cursor_position]);
+        }
+
+        /* move the cursor back to where it's supposed to be */
+        ++context.cursor_position;
+        if(echo)
+        {
+            for (int i = context.line_length; i > context.cursor_position; --i )
+            {
+                serial->write('\b');
+            }
+        }
+
+        context.line[context.line_length] = 0;
+    }
+
+    /*************************************************************************************************/
+    void remove_char(bool echo)
+    {
+        /* back the rest of the line up a character */
+        for (int i = context.cursor_position; i < context.line_length; ++i )
+        {
+            context.line[i] = context.line[i + 1];
+        }
+
+        --context.line_length;
+
+        if(echo)
+        {
+            /* print out the modified part of the ConsoleBuffer */
+            serial->write( &context.line[context.cursor_position] );
+            /* overwrite the extra character at the end */
+            serial->write(" \b");
+
+
+            /* move the cursor back to where it's supposed to be */
+            for (int i = context.line_length; i > context.cursor_position; --i )
+            {
+                serial->write( '\b' );
+            }
+        }
+    }
+
+    /*************************************************************************************************/
+    bool update_cursor_position(bool move_right)
+    {
+        bool updated = false;
+
+        if(move_right)
+        {
+            if(context.cursor_position < context.line_length)
+            {
+                ++context.cursor_position;
+                updated = true;
+                serial->write( "\x1B[C");
+            }
+        }
+        else
+        {
+            if(context.cursor_position > 0)
+            {
+                --context.cursor_position;
+                updated = true;
+                serial->write("\x1B[D");
+            }
+        }
+
+        return updated;
+    }
+
+    /*************************************************************************************************/
+    void clear_line()
+    {
+        int len = context.line_length - context.cursor_position;
+        while(len-- > 0)
+        {
+            serial->write(' ');
+        }
+        len = context.line_length;
+        while(len-- > 0)
+        {
+            serial->write("\b \b");
+        }
+        context.cursor_position = 0;
+        context.line_length = 0;
+        context.line[0] = 0;
+    }
+
+    /*************************************************************************************************/
+    void move_cursor_position(bool far_right)
+    {
+        while(update_cursor_position(far_right))
+        {
+        }
+    }
+
+    /*************************************************************************************************/
+    void clear_tab_choices(void)
+    {
+        if(context.tab_info.choices != NULL)
+        {
+            free(context.tab_info.choices);
+            context.tab_info.choices = NULL;
+        }
+    }
+
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/log/log.cpp	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,78 @@
+/*
+ * 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 <stdio.h>
+#include <stdarg.h>
+
+
+#include "Wiconnect.h"
+#include "log.h"
+#include "util/CommandProcessor/CommandProcessor.h"
+
+
+extern ConsoleSerial consoleSerial;
+
+
+/*************************************************************************************************/
+void logDebug(const char *msg, ...)
+{
+    va_list args;
+
+    consoleSerial.write("[DEBUG] ");
+    va_start(args, msg);
+    consoleSerial.vprintf(msg, args);
+    va_end(args);
+}
+
+/*************************************************************************************************/
+void logInfo(const char *msg, ...)
+{
+    va_list args;
+    consoleSerial.write("[INFO] ");
+    va_start(args, msg);
+    consoleSerial.vprintf(msg, args);
+    va_end(args);
+}
+
+/*************************************************************************************************/
+void logWrite(const void *data, int size)
+{
+    consoleSerial.write(data, size);
+}
+
+/*************************************************************************************************/
+void logInfoWriteStr(const char *msg, const char *s)
+{
+    consoleSerial.printf("[INFO] %s", msg);
+    consoleSerial.write(s);
+    consoleSerial.write("\r\n");
+}
+
+/*************************************************************************************************/
+void logError(const char *msg, ...)
+{
+    va_list args;
+    consoleSerial.write("[ERROR] ");
+    va_start(args, msg);
+    consoleSerial.vprintf(msg, args);
+    va_end(args);
+}
+
+/*************************************************************************************************/
+void logWiconnectError(WiconnectResult result, const char *msg, ...)
+{
+    va_list args;
+    consoleSerial.write("[ERROR] ");
+    va_start(args, msg);
+    consoleSerial.printf("%s, (%d) %s\r\n", msg, result, Wiconnect::getWiconnectResultStr(result));
+    va_end(args);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/log/log.h	Mon Aug 11 11:31:32 2014 +0000
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Wiconnect.h"
+
+#define LOG_DEBUG(msg, ...) logDebug(msg "\r\n", ## __VA_ARGS__)
+#define LOG_INFO(msg, ...) logInfo(msg "\r\n", ## __VA_ARGS__)
+#define LOG_INFO_WRITE_STR(msg, s) logInfoWriteStr(msg, s)
+#define LOG_ERROR(msg, ...) logError(msg "\r\n", ## __VA_ARGS__)
+#define LOG_WICONNECT_ERROR(result, msg, ...) logWiconnectError(result, msg, ## __VA_ARGS__)
+
+
+void logDebug(const char *msg, ...);
+void logInfo(const char *msg, ...);
+void logInfoWriteStr(const char *msg, const char *s);
+void logError(const char *msg, ...);
+void logWiconnectError(wiconnect::WiconnectResult result, const char *msg, ...);
+void logWrite(const void *data, int size);
+