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

Committer:
dan_ackme
Date:
Tue Aug 26 16:38:19 2014 -0700
Revision:
21:17bb3eddcbae
Add TCP server API

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dan_ackme 21:17bb3eddcbae 1 /**
dan_ackme 21:17bb3eddcbae 2 * ACKme WiConnect Host Library is licensed under the BSD licence:
dan_ackme 21:17bb3eddcbae 3 *
dan_ackme 21:17bb3eddcbae 4 * Copyright (c)2014 ACKme Networks.
dan_ackme 21:17bb3eddcbae 5 * All rights reserved.
dan_ackme 21:17bb3eddcbae 6 *
dan_ackme 21:17bb3eddcbae 7 * Redistribution and use in source and binary forms, with or without modification,
dan_ackme 21:17bb3eddcbae 8 * are permitted provided that the following conditions are met:
dan_ackme 21:17bb3eddcbae 9 *
dan_ackme 21:17bb3eddcbae 10 * 1. Redistributions of source code must retain the above copyright notice,
dan_ackme 21:17bb3eddcbae 11 * this list of conditions and the following disclaimer.
dan_ackme 21:17bb3eddcbae 12 * 2. Redistributions in binary form must reproduce the above copyright notice,
dan_ackme 21:17bb3eddcbae 13 * this list of conditions and the following disclaimer in the documentation
dan_ackme 21:17bb3eddcbae 14 * and/or other materials provided with the distribution.
dan_ackme 21:17bb3eddcbae 15 * 3. The name of the author may not be used to endorse or promote products
dan_ackme 21:17bb3eddcbae 16 * derived from this software without specific prior written permission.
dan_ackme 21:17bb3eddcbae 17 *
dan_ackme 21:17bb3eddcbae 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED
dan_ackme 21:17bb3eddcbae 19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
dan_ackme 21:17bb3eddcbae 20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
dan_ackme 21:17bb3eddcbae 21 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
dan_ackme 21:17bb3eddcbae 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
dan_ackme 21:17bb3eddcbae 23 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
dan_ackme 21:17bb3eddcbae 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
dan_ackme 21:17bb3eddcbae 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
dan_ackme 21:17bb3eddcbae 26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
dan_ackme 21:17bb3eddcbae 27 * OF SUCH DAMAGE.
dan_ackme 21:17bb3eddcbae 28 */
dan_ackme 21:17bb3eddcbae 29
dan_ackme 21:17bb3eddcbae 30 #include "Wiconnect.h"
dan_ackme 21:17bb3eddcbae 31 #include "internal/common.h"
dan_ackme 21:17bb3eddcbae 32 #include "StringUtil.h"
dan_ackme 21:17bb3eddcbae 33
dan_ackme 21:17bb3eddcbae 34 #include "types/SocketIrqHandlerMap.h"
dan_ackme 21:17bb3eddcbae 35
dan_ackme 21:17bb3eddcbae 36 #define TCP_SERVER_MONITOR_PERIOD 250 //ms
dan_ackme 21:17bb3eddcbae 37
dan_ackme 21:17bb3eddcbae 38
dan_ackme 21:17bb3eddcbae 39
dan_ackme 21:17bb3eddcbae 40 static WiconnectResult parseIpPortStr(char *str, uint32_t *ipAddress, uint16_t *port);
dan_ackme 21:17bb3eddcbae 41
dan_ackme 21:17bb3eddcbae 42
dan_ackme 21:17bb3eddcbae 43
dan_ackme 21:17bb3eddcbae 44
dan_ackme 21:17bb3eddcbae 45 /*************************************************************************************************/
dan_ackme 21:17bb3eddcbae 46 WiconnectResult SocketInterface::tcpListen(uint16_t listeningPort, int maxClients, Pin irqPin)
dan_ackme 21:17bb3eddcbae 47 {
dan_ackme 21:17bb3eddcbae 48 WiconnectResult result = WICONNECT_ERROR;
dan_ackme 21:17bb3eddcbae 49
dan_ackme 21:17bb3eddcbae 50 enum
dan_ackme 21:17bb3eddcbae 51 {
dan_ackme 21:17bb3eddcbae 52 FS_SET_MAX_CLIENTS,
dan_ackme 21:17bb3eddcbae 53 FS_SET_DATA_GPIO,
dan_ackme 21:17bb3eddcbae 54 FS_START_SERVER,
dan_ackme 21:17bb3eddcbae 55 };
dan_ackme 21:17bb3eddcbae 56
dan_ackme 21:17bb3eddcbae 57 CHECK_OTHER_COMMAND_EXECUTING();
dan_ackme 21:17bb3eddcbae 58
dan_ackme 21:17bb3eddcbae 59 if(wiconnect->internalProcessingState == FS_SET_MAX_CLIENTS)
dan_ackme 21:17bb3eddcbae 60 {
dan_ackme 21:17bb3eddcbae 61 if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("set tcp.server.max_clients", maxClients)))
dan_ackme 21:17bb3eddcbae 62 {
dan_ackme 21:17bb3eddcbae 63 wiconnect->internalProcessingState = FS_SET_DATA_GPIO;
dan_ackme 21:17bb3eddcbae 64 }
dan_ackme 21:17bb3eddcbae 65 else if(result == WICONNECT_CMD_RESPONSE_ERROR)
dan_ackme 21:17bb3eddcbae 66 {
dan_ackme 21:17bb3eddcbae 67 // if there was a module error, then the wiconnect version probably doesn't support this option
dan_ackme 21:17bb3eddcbae 68 // just continue to the next state
dan_ackme 21:17bb3eddcbae 69 wiconnect->internalProcessingState = FS_SET_DATA_GPIO;
dan_ackme 21:17bb3eddcbae 70 }
dan_ackme 21:17bb3eddcbae 71 }
dan_ackme 21:17bb3eddcbae 72
dan_ackme 21:17bb3eddcbae 73 if(wiconnect->internalProcessingState == FS_SET_DATA_GPIO)
dan_ackme 21:17bb3eddcbae 74 {
dan_ackme 21:17bb3eddcbae 75 if(irqPin == PIN_NC)
dan_ackme 21:17bb3eddcbae 76 {
dan_ackme 21:17bb3eddcbae 77 wiconnect->internalProcessingState = FS_START_SERVER;
dan_ackme 21:17bb3eddcbae 78 }
dan_ackme 21:17bb3eddcbae 79 else
dan_ackme 21:17bb3eddcbae 80 {
dan_ackme 21:17bb3eddcbae 81 PinToGpioMapper mapper = wiconnect->pinToGpioMapper;
dan_ackme 21:17bb3eddcbae 82 if(mapper == NULL)
dan_ackme 21:17bb3eddcbae 83 {
dan_ackme 21:17bb3eddcbae 84 return WICONNECT_PINNAME_TO_GPIO_MAPPER_NULL;
dan_ackme 21:17bb3eddcbae 85 }
dan_ackme 21:17bb3eddcbae 86 int8_t gpio = mapper(irqPin);
dan_ackme 21:17bb3eddcbae 87 if(gpio == -1)
dan_ackme 21:17bb3eddcbae 88 {
dan_ackme 21:17bb3eddcbae 89 return WICONNECT_PINNAME_TO_GPIO_NO_MAPPING;
dan_ackme 21:17bb3eddcbae 90 }
dan_ackme 21:17bb3eddcbae 91 else if(!irqHandlers.pinIsRegistered(irqPin))
dan_ackme 21:17bb3eddcbae 92 {
dan_ackme 21:17bb3eddcbae 93 return WICONNECT_NOT_FOUND;
dan_ackme 21:17bb3eddcbae 94 }
dan_ackme 21:17bb3eddcbae 95 else if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("set tcp.server.data_gpio %d", gpio)))
dan_ackme 21:17bb3eddcbae 96 {
dan_ackme 21:17bb3eddcbae 97 wiconnect->internalProcessingState = FS_START_SERVER;
dan_ackme 21:17bb3eddcbae 98 }
dan_ackme 21:17bb3eddcbae 99 }
dan_ackme 21:17bb3eddcbae 100 }
dan_ackme 21:17bb3eddcbae 101
dan_ackme 21:17bb3eddcbae 102 if(wiconnect->internalProcessingState == FS_START_SERVER)
dan_ackme 21:17bb3eddcbae 103 {
dan_ackme 21:17bb3eddcbae 104 if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("tcps start %d", listeningPort)))
dan_ackme 21:17bb3eddcbae 105 {
dan_ackme 21:17bb3eddcbae 106 //#ifdef WICONNECT_ASYNC_TIMER_ENABLED
dan_ackme 21:17bb3eddcbae 107 // if(clientConnectedCallback.isValid() && !wiconnect->nonBlocking)
dan_ackme 21:17bb3eddcbae 108 // {
dan_ackme 21:17bb3eddcbae 109 // serverClientConnectedCallback = clientConnectedCallback;
dan_ackme 21:17bb3eddcbae 110 // serverMonitorTimer.start(this, &SocketInterface::serverClientMonitor, TCP_SERVER_MONITOR_PERIOD);
dan_ackme 21:17bb3eddcbae 111 // }
dan_ackme 21:17bb3eddcbae 112 //#endif
dan_ackme 21:17bb3eddcbae 113 }
dan_ackme 21:17bb3eddcbae 114 }
dan_ackme 21:17bb3eddcbae 115
dan_ackme 21:17bb3eddcbae 116 CHECK_CLEANUP_COMMAND();
dan_ackme 21:17bb3eddcbae 117
dan_ackme 21:17bb3eddcbae 118 return result;
dan_ackme 21:17bb3eddcbae 119 }
dan_ackme 21:17bb3eddcbae 120
dan_ackme 21:17bb3eddcbae 121 /*************************************************************************************************/
dan_ackme 21:17bb3eddcbae 122 WiconnectResult SocketInterface::tcpAccept(WiconnectSocket &socket, int timeoutMs)
dan_ackme 21:17bb3eddcbae 123 {
dan_ackme 21:17bb3eddcbae 124 TimeoutTimer timer;
dan_ackme 21:17bb3eddcbae 125
dan_ackme 21:17bb3eddcbae 126 do
dan_ackme 21:17bb3eddcbae 127 {
dan_ackme 21:17bb3eddcbae 128 uint8_t handle;
dan_ackme 21:17bb3eddcbae 129 uint16_t local, remote;
dan_ackme 21:17bb3eddcbae 130 uint32_t ipAddress;
dan_ackme 21:17bb3eddcbae 131 WiconnectResult result;
dan_ackme 21:17bb3eddcbae 132
dan_ackme 21:17bb3eddcbae 133 if(WICONNECT_SUCCEEDED(result, pollForServerClient(&handle, &local, &remote, &ipAddress)))
dan_ackme 21:17bb3eddcbae 134 {
dan_ackme 21:17bb3eddcbae 135 if(WICONNECT_FAILED(result, socket.init(handle, SOCKET_TYPE_TCP, Wiconnect::ipToStr(ipAddress), remote, local)))
dan_ackme 21:17bb3eddcbae 136 {
dan_ackme 21:17bb3eddcbae 137 return result;
dan_ackme 21:17bb3eddcbae 138 }
dan_ackme 21:17bb3eddcbae 139 serverConnectedClientList[handle] = true;
dan_ackme 21:17bb3eddcbae 140 return WICONNECT_SUCCESS;
dan_ackme 21:17bb3eddcbae 141 }
dan_ackme 21:17bb3eddcbae 142 else if(!(result == WICONNECT_PROCESSING || result == WICONNECT_NOT_FOUND))
dan_ackme 21:17bb3eddcbae 143 {
dan_ackme 21:17bb3eddcbae 144 return result;
dan_ackme 21:17bb3eddcbae 145 }
dan_ackme 21:17bb3eddcbae 146
dan_ackme 21:17bb3eddcbae 147 } while(timeoutMs == WICONNECT_WAIT_FOREVER || !timer.timedOut(timeoutMs));
dan_ackme 21:17bb3eddcbae 148
dan_ackme 21:17bb3eddcbae 149 return WICONNECT_TIMEOUT;
dan_ackme 21:17bb3eddcbae 150 }
dan_ackme 21:17bb3eddcbae 151
dan_ackme 21:17bb3eddcbae 152 /*************************************************************************************************/
dan_ackme 21:17bb3eddcbae 153 WiconnectResult SocketInterface::tcpServerStop(void)
dan_ackme 21:17bb3eddcbae 154 {
dan_ackme 21:17bb3eddcbae 155 WiconnectResult result = WICONNECT_ERROR;
dan_ackme 21:17bb3eddcbae 156
dan_ackme 21:17bb3eddcbae 157 CHECK_OTHER_COMMAND_EXECUTING();
dan_ackme 21:17bb3eddcbae 158
dan_ackme 21:17bb3eddcbae 159 result = wiconnect->sendCommand("tcps stop");
dan_ackme 21:17bb3eddcbae 160
dan_ackme 21:17bb3eddcbae 161 CHECK_CLEANUP_COMMAND();
dan_ackme 21:17bb3eddcbae 162
dan_ackme 21:17bb3eddcbae 163 return result;
dan_ackme 21:17bb3eddcbae 164 }
dan_ackme 21:17bb3eddcbae 165
dan_ackme 21:17bb3eddcbae 166 /*************************************************************************************************/
dan_ackme 21:17bb3eddcbae 167 WiconnectResult SocketInterface::pollForServerClient(uint8_t *handlePtr, uint16_t *localPort, uint16_t *remotePort, uint32_t *ipAddress)
dan_ackme 21:17bb3eddcbae 168 {
dan_ackme 21:17bb3eddcbae 169 WiconnectResult result;
dan_ackme 21:17bb3eddcbae 170
dan_ackme 21:17bb3eddcbae 171 CHECK_OTHER_COMMAND_EXECUTING();
dan_ackme 21:17bb3eddcbae 172
dan_ackme 21:17bb3eddcbae 173 if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("list")))
dan_ackme 21:17bb3eddcbae 174 {
dan_ackme 21:17bb3eddcbae 175 bool connectedClients[WICONNECT_MAX_SOCKETS];
dan_ackme 21:17bb3eddcbae 176 char *line, *savedLine;
dan_ackme 21:17bb3eddcbae 177 result = WICONNECT_NOT_FOUND;
dan_ackme 21:17bb3eddcbae 178
dan_ackme 21:17bb3eddcbae 179 memset(connectedClients, 0, sizeof(connectedClients));
dan_ackme 21:17bb3eddcbae 180
dan_ackme 21:17bb3eddcbae 181 for(savedLine = wiconnect->internalBuffer; (line = StringUtil::strtok_r(savedLine, "\r\n", &savedLine)) != NULL;)
dan_ackme 21:17bb3eddcbae 182 {
dan_ackme 21:17bb3eddcbae 183 char *toks[4], *savedTok;
dan_ackme 21:17bb3eddcbae 184
dan_ackme 21:17bb3eddcbae 185 if(*line != '#')
dan_ackme 21:17bb3eddcbae 186 {
dan_ackme 21:17bb3eddcbae 187 continue;
dan_ackme 21:17bb3eddcbae 188 }
dan_ackme 21:17bb3eddcbae 189 savedTok = line + 2;
dan_ackme 21:17bb3eddcbae 190
dan_ackme 21:17bb3eddcbae 191 for(int i = 0; i < 4 && (toks[i] = StringUtil::strtok_r(savedTok, " ", &savedTok)) != NULL; ++i)
dan_ackme 21:17bb3eddcbae 192 {
dan_ackme 21:17bb3eddcbae 193 if(toks[i] == NULL)
dan_ackme 21:17bb3eddcbae 194 {
dan_ackme 21:17bb3eddcbae 195 result = WICONNECT_RESPONSE_PARSE_ERROR;
dan_ackme 21:17bb3eddcbae 196 goto exit;
dan_ackme 21:17bb3eddcbae 197 }
dan_ackme 21:17bb3eddcbae 198 }
dan_ackme 21:17bb3eddcbae 199
dan_ackme 21:17bb3eddcbae 200 if(strcmp(toks[1], "TCPS") != 0)
dan_ackme 21:17bb3eddcbae 201 {
dan_ackme 21:17bb3eddcbae 202 continue;
dan_ackme 21:17bb3eddcbae 203 }
dan_ackme 21:17bb3eddcbae 204
dan_ackme 21:17bb3eddcbae 205 uint8_t handle = (uint8_t)(*toks[0] - '0');
dan_ackme 21:17bb3eddcbae 206 if(handle >= WICONNECT_MAX_SOCKETS)
dan_ackme 21:17bb3eddcbae 207 {
dan_ackme 21:17bb3eddcbae 208 result = WICONNECT_RESPONSE_PARSE_ERROR;
dan_ackme 21:17bb3eddcbae 209 goto exit;
dan_ackme 21:17bb3eddcbae 210 }
dan_ackme 21:17bb3eddcbae 211
dan_ackme 21:17bb3eddcbae 212 connectedClients[handle] = true;
dan_ackme 21:17bb3eddcbae 213
dan_ackme 21:17bb3eddcbae 214 if(result == WICONNECT_SUCCESS)
dan_ackme 21:17bb3eddcbae 215 {
dan_ackme 21:17bb3eddcbae 216 continue;
dan_ackme 21:17bb3eddcbae 217 }
dan_ackme 21:17bb3eddcbae 218 else if(serverConnectedClientList[handle])
dan_ackme 21:17bb3eddcbae 219 {
dan_ackme 21:17bb3eddcbae 220 continue;
dan_ackme 21:17bb3eddcbae 221 }
dan_ackme 21:17bb3eddcbae 222
dan_ackme 21:17bb3eddcbae 223 result = WICONNECT_SUCCESS;
dan_ackme 21:17bb3eddcbae 224
dan_ackme 21:17bb3eddcbae 225 if(handlePtr != NULL)
dan_ackme 21:17bb3eddcbae 226 {
dan_ackme 21:17bb3eddcbae 227 *handlePtr = handle;
dan_ackme 21:17bb3eddcbae 228 parseIpPortStr(toks[2], NULL, localPort);
dan_ackme 21:17bb3eddcbae 229 parseIpPortStr(toks[3], ipAddress, remotePort);
dan_ackme 21:17bb3eddcbae 230 }
dan_ackme 21:17bb3eddcbae 231 }
dan_ackme 21:17bb3eddcbae 232
dan_ackme 21:17bb3eddcbae 233 for(int i = 0; i < WICONNECT_MAX_SOCKETS; ++i)
dan_ackme 21:17bb3eddcbae 234 {
dan_ackme 21:17bb3eddcbae 235 if(connectedClients[i] == false)
dan_ackme 21:17bb3eddcbae 236 {
dan_ackme 21:17bb3eddcbae 237 serverConnectedClientList[i] = false;
dan_ackme 21:17bb3eddcbae 238 }
dan_ackme 21:17bb3eddcbae 239 }
dan_ackme 21:17bb3eddcbae 240 }
dan_ackme 21:17bb3eddcbae 241
dan_ackme 21:17bb3eddcbae 242
dan_ackme 21:17bb3eddcbae 243 exit:
dan_ackme 21:17bb3eddcbae 244 CHECK_CLEANUP_COMMAND();
dan_ackme 21:17bb3eddcbae 245
dan_ackme 21:17bb3eddcbae 246 return result;
dan_ackme 21:17bb3eddcbae 247 }
dan_ackme 21:17bb3eddcbae 248
dan_ackme 21:17bb3eddcbae 249 /*************************************************************************************************/
dan_ackme 21:17bb3eddcbae 250 static WiconnectResult parseIpPortStr(char *str, uint32_t *ipAddress, uint16_t *port)
dan_ackme 21:17bb3eddcbae 251 {
dan_ackme 21:17bb3eddcbae 252 char *colon = strchr(str, ':');
dan_ackme 21:17bb3eddcbae 253 if(colon == NULL)
dan_ackme 21:17bb3eddcbae 254 {
dan_ackme 21:17bb3eddcbae 255 return WICONNECT_RESPONSE_PARSE_ERROR;
dan_ackme 21:17bb3eddcbae 256 }
dan_ackme 21:17bb3eddcbae 257 *colon++ = 0;
dan_ackme 21:17bb3eddcbae 258
dan_ackme 21:17bb3eddcbae 259 if(ipAddress != NULL && !Wiconnect::strToIp(str, ipAddress))
dan_ackme 21:17bb3eddcbae 260 {
dan_ackme 21:17bb3eddcbae 261 return WICONNECT_RESPONSE_PARSE_ERROR;
dan_ackme 21:17bb3eddcbae 262 }
dan_ackme 21:17bb3eddcbae 263 else if(!StringUtil::strToUint16(colon, port))
dan_ackme 21:17bb3eddcbae 264 {
dan_ackme 21:17bb3eddcbae 265 return WICONNECT_RESPONSE_PARSE_ERROR;
dan_ackme 21:17bb3eddcbae 266 }
dan_ackme 21:17bb3eddcbae 267
dan_ackme 21:17bb3eddcbae 268 return WICONNECT_SUCCESS;
dan_ackme 21:17bb3eddcbae 269 }