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
Diff: TcpServer.cpp
- 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; +}