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
Child:
40:4b4306f3d829
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TcpServer.cpp	Mon Oct 27 13:42:26 2014 -0700
@@ -0,0 +1,275 @@
+/**
+ * ACKme WiConnect Host Library is licensed under the BSD licence:
+ *
+ * Copyright (c)2014 ACKme Networks.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "Wiconnect.h"
+#include "internal/common.h"
+#include "api/StringUtil.h"
+
+#ifdef WICONNECT_GPIO_IRQ_ENABLED
+#include "api/types/SocketIrqHandlerMap.h"
+#endif
+
+#define TCP_SERVER_MONITOR_PERIOD 250 //ms
+
+
+
+static WiconnectResult parseIpPortStr(char *str, uint32_t *ipAddress, uint16_t *port);
+
+
+
+
+/*************************************************************************************************/
+WiconnectResult SocketInterface::tcpListen(uint16_t listeningPort, int maxClients GPIO_IRQ_ARG)
+{
+    WiconnectResult result = WICONNECT_ERROR;
+
+    enum
+    {
+        FS_SET_MAX_CLIENTS,
+        FS_SET_DATA_GPIO,
+        FS_START_SERVER,
+    };
+
+    CHECK_OTHER_COMMAND_EXECUTING();
+
+    if(wiconnect->internalProcessingState == FS_SET_MAX_CLIENTS)
+    {
+        if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("set tcp.server.max_clients", maxClients)))
+        {
+            wiconnect->internalProcessingState = FS_SET_DATA_GPIO;
+        }
+        else if(result == WICONNECT_CMD_RESPONSE_ERROR)
+        {
+            // if there was a module error, then the wiconnect version probably doesn't support this option
+            // just continue to the next state
+            wiconnect->internalProcessingState = FS_SET_DATA_GPIO;
+        }
+    }
+
+    if(wiconnect->internalProcessingState == FS_SET_DATA_GPIO)
+    {
+#ifdef WICONNECT_GPIO_IRQ_ENABLED
+        if(irqPin == PIN_NC)
+        {
+            wiconnect->internalProcessingState = FS_START_SERVER;
+        }
+        else
+        {
+            PinToGpioMapper mapper = wiconnect->pinToGpioMapper;
+            if(mapper == NULL)
+            {
+                return WICONNECT_PINNAME_TO_GPIO_MAPPER_NULL;
+            }
+            int8_t gpio = mapper(irqPin);
+            if(gpio == -1)
+            {
+                return WICONNECT_PINNAME_TO_GPIO_NO_MAPPING;
+            }
+            else if(!irqHandlers.pinIsRegistered(irqPin))
+            {
+                return WICONNECT_NOT_FOUND;
+            }
+            else if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("set tcp.server.data_gpio %d", gpio)))
+            {
+                wiconnect->internalProcessingState = FS_START_SERVER;
+            }
+        }
+#else
+        wiconnect->internalProcessingState = FS_START_SERVER;
+#endif
+    }
+
+    if(wiconnect->internalProcessingState == FS_START_SERVER)
+    {
+        if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("tcps start %d", listeningPort)))
+        {
+//#ifdef WICONNECT_ASYNC_TIMER_ENABLED
+//            if(clientConnectedCallback.isValid() && !wiconnect->nonBlocking)
+//            {
+//                serverClientConnectedCallback = clientConnectedCallback;
+//                serverMonitorTimer.start(this, &SocketInterface::serverClientMonitor, TCP_SERVER_MONITOR_PERIOD);
+//            }
+//#endif
+        }
+    }
+
+    CHECK_CLEANUP_COMMAND();
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult SocketInterface::tcpAccept(WiconnectSocket &socket, uint32_t timeoutMs)
+{
+    TimeoutTimer timer;
+
+    do
+    {
+        uint8_t handle;
+        uint16_t local, remote;
+        uint32_t ipAddress;
+        WiconnectResult result;
+
+        if(WICONNECT_SUCCEEDED(result, pollForServerClient(&handle, &local, &remote, &ipAddress)))
+        {
+            char ipBuffer[17];
+            if(WICONNECT_FAILED(result, socket.init(handle, SOCKET_TYPE_TCP, Wiconnect::ipToStr(ipAddress, ipBuffer), remote, local)))
+            {
+                return result;
+            }
+            serverConnectedClientList |= (1 << handle);
+            return WICONNECT_SUCCESS;
+        }
+        else if(!(result == WICONNECT_PROCESSING || result == WICONNECT_NOT_FOUND))
+        {
+            return result;
+        }
+
+    } while(timeoutMs == WICONNECT_WAIT_FOREVER || !timer.timedOut(timeoutMs));
+
+    return WICONNECT_TIMEOUT;
+}
+
+/*************************************************************************************************/
+WiconnectResult SocketInterface::tcpServerStop(void)
+{
+    WiconnectResult result = WICONNECT_ERROR;
+
+    CHECK_OTHER_COMMAND_EXECUTING();
+
+    result = wiconnect->sendCommand("tcps stop");
+
+    CHECK_CLEANUP_COMMAND();
+
+    return result;
+}
+
+/*************************************************************************************************/
+WiconnectResult SocketInterface::pollForServerClient(uint8_t *handlePtr, uint16_t *localPort, uint16_t *remotePort, uint32_t *ipAddress)
+{
+    WiconnectResult result;
+
+    CHECK_OTHER_COMMAND_EXECUTING();
+
+    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("list")))
+    {
+        uint32_t connectedClients = 0;
+        char *line, *savedLine;
+        result = WICONNECT_NOT_FOUND;
+
+        for(savedLine = wiconnect->internalBuffer; (line = StringUtil::strtok_r(savedLine, "\r\n", &savedLine)) != NULL;)
+        {
+            char *toks[4], *savedTok;
+
+            if(*line != '#')
+            {
+                continue;
+            }
+            savedTok = line + 2;
+
+            for(int i = 0; i < 4 && (toks[i] = StringUtil::strtok_r(savedTok, " ", &savedTok)) != NULL; ++i)
+            {
+                if(toks[i] == NULL)
+                {
+                    result = WICONNECT_RESPONSE_PARSE_ERROR;
+                    goto exit;
+                }
+            }
+
+            if(strcmp(toks[1], "TCPS") != 0)
+            {
+                continue;
+            }
+
+            uint8_t handle = (uint8_t)(*toks[0] - '0');
+            if(handle >= WICONNECT_MAX_SOCKETS)
+            {
+                result = WICONNECT_RESPONSE_PARSE_ERROR;
+                goto exit;
+            }
+            const uint32_t handleMask = (1 << handle);
+            connectedClients |= handleMask;
+
+            if(result == WICONNECT_SUCCESS)
+            {
+                continue;
+            }
+            else if(serverConnectedClientList & handleMask)
+            {
+                continue;
+            }
+
+            result = WICONNECT_SUCCESS;
+
+            if(handlePtr != NULL)
+            {
+                *handlePtr = handle;
+                parseIpPortStr(toks[2], NULL, localPort);
+                parseIpPortStr(toks[3], ipAddress, remotePort);
+            }
+        }
+
+        uint32_t mask = 1;
+        for(int i = 0; i < WICONNECT_MAX_SOCKETS; ++i, mask <<= 1)
+        {
+            if(!(connectedClients & mask))
+            {
+                serverConnectedClientList &= ~mask;
+            }
+        }
+    }
+
+
+exit:
+    CHECK_CLEANUP_COMMAND();
+
+    return result;
+}
+
+/*************************************************************************************************/
+static WiconnectResult parseIpPortStr(char *str, uint32_t *ipAddress, uint16_t *port)
+{
+    char *colon = strchr(str, ':');
+    if(colon == NULL)
+    {
+        return WICONNECT_RESPONSE_PARSE_ERROR;
+    }
+    *colon++ = 0;
+
+    if(ipAddress != NULL && !Wiconnect::strToIp(str, ipAddress))
+    {
+        return WICONNECT_RESPONSE_PARSE_ERROR;
+    }
+    else if(!StringUtil::strToUint16(colon, port))
+    {
+        return WICONNECT_RESPONSE_PARSE_ERROR;
+    }
+
+    return WICONNECT_SUCCESS;
+}