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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WiconnectSocket.cpp Source File

WiconnectSocket.cpp

00001 /**
00002  * ACKme WiConnect Host Library is licensed under the BSD licence: 
00003  * 
00004  * Copyright (c)2014 ACKme Networks.
00005  * All rights reserved. 
00006  * 
00007  * Redistribution and use in source and binary forms, with or without modification, 
00008  * are permitted provided that the following conditions are met: 
00009  * 
00010  * 1. Redistributions of source code must retain the above copyright notice, 
00011  * this list of conditions and the following disclaimer. 
00012  * 2. Redistributions in binary form must reproduce the above copyright notice, 
00013  * this list of conditions and the following disclaimer in the documentation 
00014  * and/or other materials provided with the distribution. 
00015  * 3. The name of the author may not be used to endorse or promote products 
00016  * derived from this software without specific prior written permission. 
00017  * 
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED 
00019  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00020  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
00021  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00022  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
00023  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
00026  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
00027  * OF SUCH DAMAGE.
00028  */
00029 #include <stdarg.h>
00030 #include "Wiconnect.h"
00031 #include "internal/common.h"
00032 #include "api/StringUtil.h"
00033 
00034 
00035 #define CHECK_CONNECTED() if(!isConnected()) return WICONNECT_NOT_CONNECTED
00036 
00037 
00038 WiconnectResult readerCallback(void *user, void *data, int maxReadSize, int *bytesRead);
00039 
00040 
00041 
00042 /*************************************************************************************************/
00043 WiconnectSocket::WiconnectSocket(int rxBufferLen_, void *rxBuffer_, int txBufferLen_, void *txBuffer_)
00044 {
00045     wiconnect = Wiconnect::getInstance();
00046 
00047     memset((void*)&txBuffer, 0, sizeof(Buffer));
00048     memset((void*)&rxBuffer, 0, sizeof(Buffer));
00049 
00050     txBuffer.size = txBufferLen_;
00051     txBuffer.buffer = (uint8_t*)txBuffer_;
00052 
00053     rxBuffer.size = rxBufferLen_;
00054     rxBuffer.buffer = (uint8_t*)rxBuffer_;
00055 
00056     if(txBuffer.size > 0)
00057     {
00058         if(txBuffer_ == NULL)
00059         {
00060 #ifdef WICONNECT_ENABLE_MALLOC
00061             wiconnect_assert(wiconnect, "Socket(), malloc not defined", wiconnect->_malloc != NULL);
00062             txBuffer.buffer = (uint8_t*)wiconnect->_malloc(txBufferLen_);
00063             wiconnect_assert(wiconnect, "Socket(), txBuffer malloc failed", txBuffer.buffer != NULL);
00064             txBuffer.allocated = true;
00065 #else
00066             wiconnect_assert(wiconnect, "must specify buffer", 0);
00067 #endif
00068         }
00069         txBuffer.size -= 4;
00070     }
00071 
00072     if(rxBuffer.size > 0)
00073     {
00074         if(rxBuffer_ == NULL)
00075         {
00076 #ifdef WICONNECT_ENABLE_MALLOC
00077             wiconnect_assert(wiconnect, "Socket(), malloc not defined", wiconnect->_malloc != NULL);
00078             rxBuffer.buffer = (uint8_t*)wiconnect->_malloc(rxBufferLen_);
00079             wiconnect_assert(wiconnect, "Socket(), rxBuffer malloc failed", rxBuffer.buffer != NULL);
00080             rxBuffer.allocated = true;
00081 #else
00082             wiconnect_assert(wiconnect, "must specify buffer", 0);
00083 #endif
00084         }
00085         rxBuffer.size -= 4;
00086     }
00087 
00088     handle = SOCKET_INVALID_HANDLE;
00089     type = SOCKET_TYPE_UNKNOWN;
00090     remotePort = 0;
00091     localPort = 0;
00092     connected = false;
00093     enableAutoClose = false;
00094     host[0] = 0;
00095 }
00096 
00097 
00098 /*************************************************************************************************/
00099 WiconnectResult WiconnectSocket::init(uint8_t handle_, SocketType type_, const char *host_, uint16_t remotePort_, uint16_t localPort_)
00100 {
00101     handle = handle_;
00102     type = type_;
00103     remotePort = remotePort_;
00104     localPort = localPort_;
00105     connected = true;
00106     enableAutoClose = false;
00107 
00108     rxBuffer.ptr = rxBuffer.buffer;
00109     rxBuffer.bytesPending = 0;
00110     txBuffer.ptr = txBuffer.buffer;
00111     txBuffer.bytesPending = 0;
00112 
00113     strncpy(host, host_, sizeof(host)-1);
00114 
00115     return WICONNECT_SUCCESS;
00116 }
00117 
00118 /*************************************************************************************************/
00119 WiconnectSocket::~WiconnectSocket()
00120 {
00121     while((handle != SOCKET_INVALID_HANDLE) && (close() == WICONNECT_PROCESSING))
00122     {
00123     }
00124 
00125 #ifdef WICONNECT_ENABLE_MALLOC
00126     if(txBuffer.allocated && txBuffer.size > 0)
00127     {
00128         wiconnect_assert(wiconnect, "~Socket(), free not defined", wiconnect->_free != NULL);
00129         wiconnect->_free(txBuffer.buffer);
00130     }
00131     if(rxBuffer.allocated && rxBuffer.size > 0)
00132     {
00133         wiconnect_assert(wiconnect, "~Socket(), free not defined", wiconnect->_free != NULL);
00134         wiconnect->_free(rxBuffer.buffer);
00135     }
00136 #endif
00137 }
00138 
00139 /*************************************************************************************************/
00140 bool WiconnectSocket::isConnected()
00141 {
00142     return connected;
00143 }
00144 
00145 /*************************************************************************************************/
00146 SocketType WiconnectSocket::getType()
00147 {
00148     return type;
00149 }
00150 
00151 /*************************************************************************************************/
00152 const char* WiconnectSocket::getHost()
00153 {
00154     return host;
00155 }
00156 
00157 /*************************************************************************************************/
00158 uint16_t WiconnectSocket::getLocalPort()
00159 {
00160     return localPort;
00161 }
00162 
00163 /*************************************************************************************************/
00164 uint16_t WiconnectSocket::getRemotePort()
00165 {
00166     return remotePort;
00167 }
00168 
00169 /*************************************************************************************************/
00170 uint8_t WiconnectSocket::getHandle()
00171 {
00172     return handle;
00173 }
00174 
00175 
00176 /*************************************************************************************************/
00177 WiconnectResult WiconnectSocket::close()
00178 {
00179     WiconnectResult result;
00180     CHECK_CONNECTED();
00181     CHECK_OTHER_COMMAND_EXECUTING();
00182 
00183     result = wiconnect->sendCommand("close %d", handle);
00184 
00185     if(result != WICONNECT_PROCESSING)
00186     {
00187         connected = false;
00188         wiconnect->socketClosedCallback(this);
00189     }
00190 
00191     CHECK_CLEANUP_COMMAND();
00192 
00193     return result;
00194 }
00195 
00196 /*************************************************************************************************/
00197 WiconnectResult WiconnectSocket::poll(bool *rxDataAvailablePtr, bool autoClose)
00198 {
00199     WiconnectResult result;
00200     int32_t status;
00201     bool autoClosed = false;
00202 
00203     *rxDataAvailablePtr = false;
00204 
00205     CHECK_CONNECTED();
00206 
00207     if(rxBuffer.size > 0 && WICONNECT_IS_IDLE())
00208     {
00209         if(rxBuffer.ptr < &rxBuffer.buffer[rxBuffer.bytesPending])
00210         {
00211             *rxDataAvailablePtr = true;
00212             return WICONNECT_SUCCESS;
00213         }
00214         else if(read() == WICONNECT_SUCCESS && (rxBuffer.ptr < &rxBuffer.buffer[rxBuffer.bytesPending]))
00215         {
00216             *rxDataAvailablePtr = true;
00217             return WICONNECT_SUCCESS;
00218         }
00219     }
00220 
00221     CHECK_OTHER_COMMAND_EXECUTING();
00222 
00223     if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("poll %d", handle)))
00224     {
00225         if(!WICONNECT_FAILED(result, wiconnect->responseToInt32(&status)))
00226         {
00227             if(status > 0)
00228             {
00229                 if(status == 2 && enableAutoClose)
00230                 {
00231                     autoClosed = autoClose;
00232                     *rxDataAvailablePtr = false;
00233                 }
00234                 else
00235                 {
00236                     *rxDataAvailablePtr = true;
00237                 }
00238             }
00239         }
00240     }
00241 
00242     CHECK_CLEANUP_COMMAND();
00243 
00244     // if we auto-closed, then block until everything is cleaned-up
00245     if(autoClosed)
00246     {
00247         while(WICONNECT_IS_PROCESSING(result, close()))
00248         {
00249         }
00250     }
00251 
00252     return result;
00253 }
00254 
00255 /*************************************************************************************************/
00256 WiconnectResult WiconnectSocket::write(int length, bool flush)
00257 {
00258     CHECK_CONNECTED();
00259 
00260     if( txBuffer.size == 0)
00261     {
00262         return WICONNECT_UNSUPPORTED;
00263     }
00264     else if(length > txBuffer.size)
00265     {
00266         return WICONNECT_OVERFLOW;
00267     }
00268     txBuffer.bytesPending = length;
00269 
00270     return flush ? flushTxBuffer() : WICONNECT_SUCCESS;
00271 }
00272 
00273 /*************************************************************************************************/
00274 WiconnectResult WiconnectSocket::write(const void* buffer, int length, bool flush)
00275 {
00276     WiconnectResult result = WICONNECT_SUCCESS;
00277     CHECK_CONNECTED();
00278 
00279     if(txBuffer.size > 0)
00280     {
00281         const uint8_t *src = (const uint8_t *)buffer;
00282 
00283         while(length > 0)
00284         {
00285             int bytesToWrite = MIN(length, txBuffer.size - txBuffer.bytesPending);
00286             uint8_t *dst = (uint8_t*)&txBuffer.buffer[txBuffer.bytesPending];
00287             memcpy(dst, src, bytesToWrite);
00288             txBuffer.bytesPending += bytesToWrite;
00289             length -= bytesToWrite;
00290             src += bytesToWrite;
00291 
00292             if((txBuffer.bytesPending >= txBuffer.size) &&
00293                 WICONNECT_FAILED(result, flushTxBuffer()))
00294             {
00295                  break;
00296             }
00297         }
00298 
00299         if(flush && txBuffer.bytesPending > 0)
00300         {
00301             result = flushTxBuffer();
00302         }
00303     }
00304     else
00305     {
00306         if(WICONNECT_IS_IDLE())
00307         {
00308             txBuffer.ptr = (uint8_t*)buffer;
00309             txBuffer.bytesPending = length;
00310         }
00311 
00312         result = flushTxBuffer();
00313     }
00314 
00315 
00316     return result;
00317 }
00318 
00319 /*************************************************************************************************/
00320 WiconnectResult WiconnectSocket::read(void* buffer, uint16_t maxLength, uint16_t *bytesReadPtr)
00321 {
00322     WiconnectResult result;
00323 
00324     CHECK_CONNECTED();
00325 
00326     if(rxBuffer.size > 0)
00327     {
00328         uint16_t bytesToRead = 0;
00329         const uint16_t bufferedBytes = (&rxBuffer.buffer[rxBuffer.bytesPending] - rxBuffer.ptr);
00330         if(bufferedBytes > 0)
00331         {
00332             bytesToRead = MIN(bufferedBytes, maxLength);
00333             memcpy(buffer, rxBuffer.ptr, bytesToRead);
00334             rxBuffer.ptr += bytesToRead;
00335             *bytesReadPtr = bytesToRead;
00336         }
00337         if(rxBuffer.ptr >= &rxBuffer.buffer[rxBuffer.bytesPending])
00338         {
00339             clearRxBuffer();
00340         }
00341         if(bytesToRead > 0)
00342         {
00343             return WICONNECT_SUCCESS;
00344         }
00345     }
00346 
00347     CHECK_OTHER_COMMAND_EXECUTING();
00348 
00349     if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand((char*)buffer, maxLength, "read %d %d", handle, maxLength)))
00350     {
00351         const uint16_t bytesRead = wiconnect->getLastCommandResponseLength();
00352         enableAutoClose = (bytesRead == 0);
00353         *bytesReadPtr = bytesRead;
00354     }
00355 
00356     CHECK_CLEANUP_COMMAND();
00357 
00358     return result;
00359 }
00360 
00361 /*************************************************************************************************/
00362 WiconnectResult WiconnectSocket::read(uint8_t **bufferPtr, uint16_t *bytesReadPtr)
00363 {
00364     WiconnectResult result = WICONNECT_SUCCESS;
00365 
00366     CHECK_CONNECTED();
00367 
00368     if(rxBuffer.size == 0)
00369     {
00370         return WICONNECT_UNSUPPORTED;
00371     }
00372     else if(bufferPtr != NULL && bytesReadPtr == NULL)
00373     {
00374         return WICONNECT_BAD_ARG;
00375     }
00376 
00377     if(rxBuffer.ptr >= &rxBuffer.buffer[rxBuffer.bytesPending])
00378     {
00379         clearRxBuffer();
00380     }
00381 
00382     if(rxBuffer.bytesPending < rxBuffer.size)
00383     {
00384         const int bytesToRead = rxBuffer.size - rxBuffer.bytesPending;
00385         char* ptr = (char*)&rxBuffer.buffer[rxBuffer.bytesPending];
00386 
00387         CHECK_OTHER_COMMAND_EXECUTING();
00388 
00389         loop:
00390         if(bytesToRead > 0 && WICONNECT_SUCCEEDED(result, wiconnect->sendCommand(ptr, bytesToRead, "read %d %d", handle, bytesToRead)))
00391         {
00392             const uint16_t bytesRead = wiconnect->getLastCommandResponseLength();
00393             enableAutoClose = (bytesRead == 0);
00394             rxBuffer.bytesPending += bytesRead;
00395         }
00396 
00397         // if still processing and in non-blocking mode,
00398         // then this api call must block until the command completes
00399         if(result == WICONNECT_PROCESSING && wiconnect->nonBlocking)
00400         {
00401             goto loop;
00402         }
00403 
00404         CHECK_CLEANUP_COMMAND();
00405     }
00406 
00407     if(bufferPtr != NULL)
00408     {
00409         *bufferPtr = rxBuffer.buffer;
00410         *bytesReadPtr = rxBuffer.bytesPending;
00411         clearRxBuffer();
00412     }
00413 
00414     return result;
00415 }
00416 
00417 /*************************************************************************************************/
00418 WiconnectResult WiconnectSocket::getc(uint8_t *c)
00419 {
00420     WiconnectResult result;
00421 
00422     if(rxBuffer.size == 0)
00423     {
00424         return WICONNECT_UNSUPPORTED;
00425     }
00426 
00427     if(rxBuffer.bytesPending == 0 &&
00428       WICONNECT_FAILED(result, read()))
00429     {
00430         return result;
00431     }
00432     else if(rxBuffer.ptr < &rxBuffer.buffer[rxBuffer.bytesPending])
00433     {
00434         *c = *rxBuffer.ptr;
00435         ++rxBuffer.ptr;
00436         return WICONNECT_SUCCESS;
00437     }
00438     else
00439     {
00440         clearRxBuffer();
00441         return WICONNECT_ERROR;
00442     }
00443 }
00444 
00445 /*************************************************************************************************/
00446 WiconnectResult WiconnectSocket::putc(uint8_t c, bool flush)
00447 {
00448     WiconnectResult result = WICONNECT_SUCCESS;
00449     CHECK_CONNECTED();
00450 
00451     if(txBuffer.size == 0)
00452     {
00453         return WICONNECT_UNSUPPORTED;
00454     }
00455     else if(txBuffer.bytesPending < txBuffer.size)
00456     {
00457         uint8_t *ptr = (uint8_t*)&txBuffer.buffer[txBuffer.bytesPending];
00458         *ptr = c;
00459         ++txBuffer.bytesPending;
00460 
00461         if(flush || txBuffer.bytesPending >= txBuffer.size)
00462         {
00463             result = flushTxBuffer();
00464         }
00465     }
00466     else
00467     {
00468         result = WICONNECT_OVERFLOW;
00469     }
00470 
00471     return result;
00472 }
00473 
00474 /*************************************************************************************************/
00475 WiconnectResult WiconnectSocket::puts(const char *s, bool flush)
00476 {
00477     const int len = strlen(s);
00478     return write(s, len, flush);
00479 }
00480 
00481 /*************************************************************************************************/
00482 WiconnectResult WiconnectSocket::printf(const char* format, ...)
00483 {
00484     WiconnectResult result = WICONNECT_SUCCESS;
00485 
00486     CHECK_CONNECTED();
00487     if(txBuffer.size == 0)
00488     {
00489         return WICONNECT_UNSUPPORTED;
00490     }
00491 
00492     const int available = txBuffer.size - txBuffer.bytesPending;
00493     char *ptr = (char*)&txBuffer.buffer[txBuffer.bytesPending];
00494     va_list args;
00495     va_start(args, format);
00496     const int len = vsnprintf(ptr, available, format, args);
00497     if(len > available)
00498     {
00499         return WICONNECT_OVERFLOW;
00500     }
00501     else
00502     {
00503         txBuffer.bytesPending += len;
00504     }
00505 
00506     if(txBuffer.bytesPending >= txBuffer.size)
00507     {
00508         result = flushTxBuffer();
00509     }
00510 
00511     return result;
00512 }
00513 
00514 
00515 /*************************************************************************************************/
00516 WiconnectResult WiconnectSocket::flushTxBuffer()
00517 {
00518     WiconnectResult result = WICONNECT_SUCCESS;
00519 
00520     CHECK_CONNECTED();
00521 
00522     if(txBuffer.size == 0)
00523     {
00524         CHECK_OTHER_COMMAND_EXECUTING();
00525     }
00526 
00527     if(txBuffer.bytesPending > 0)
00528     {
00529         loop:
00530         result = wiconnect->sendCommand(ReaderFunc(readerCallback), &this->txBuffer, "write %u %u", handle, txBuffer.bytesPending);
00531 
00532         // if still processing and in non-blocking mode and using a txtBuffer,
00533         // then this api call must block until the command completes
00534         if(result == WICONNECT_PROCESSING && wiconnect->nonBlocking && txBuffer.size > 0)
00535         {
00536             goto loop;
00537         }
00538     }
00539 
00540     if(txBuffer.size == 0)
00541     {
00542         CHECK_CLEANUP_COMMAND();
00543     }
00544 
00545     if(result != WICONNECT_PROCESSING)
00546     {
00547         txBuffer.ptr = txBuffer.buffer;
00548         txBuffer.bytesPending = 0;
00549     }
00550 
00551     return result;
00552 }
00553 
00554 
00555 
00556 /*************************************************************************************************/
00557 void WiconnectSocket::clearRxBuffer()
00558 {
00559     rxBuffer.bytesPending = 0;
00560     rxBuffer.ptr = rxBuffer.buffer;
00561 }
00562 
00563 /*************************************************************************************************/
00564 uint8_t* WiconnectSocket::getTxBuffer()
00565 {
00566     return txBuffer.buffer;
00567 }
00568 /*************************************************************************************************/
00569 int WiconnectSocket::getTxBufferSize()
00570 {
00571     return txBuffer.size;
00572 }
00573 /*************************************************************************************************/
00574 int WiconnectSocket::getTxBufferBytesPending()
00575 {
00576     return txBuffer.bytesPending;
00577 }
00578 /*************************************************************************************************/
00579 uint8_t* WiconnectSocket::getRxBuffer()
00580 {
00581     return rxBuffer.buffer;
00582 }
00583 /*************************************************************************************************/
00584 int WiconnectSocket::getRxBufferSize()
00585 {
00586     return rxBuffer.size;
00587 }
00588 /*************************************************************************************************/
00589 int WiconnectSocket::getRxBufferBytesPending()
00590 {
00591     return rxBuffer.bytesPending;
00592 }
00593 
00594 
00595 /*************************************************************************************************/
00596 WiconnectResult readerCallback(void *user, void *data, int maxReadSize, int *bytesRead)
00597 {
00598     Buffer *txBuffer = (Buffer*)user;
00599 
00600     if(txBuffer->bytesPending == 0)
00601     {
00602         *bytesRead = EOF;
00603     }
00604     else
00605     {
00606         const int bytesToWrite = MIN(maxReadSize, txBuffer->bytesPending);
00607         memcpy(data, txBuffer->ptr, bytesToWrite);
00608         txBuffer->ptr += bytesToWrite;
00609         txBuffer->bytesPending -= bytesToWrite;
00610         *bytesRead = bytesToWrite;
00611     }
00612 
00613     return WICONNECT_SUCCESS;
00614 }
00615