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
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
Generated on Tue Jul 12 2022 17:35:59 by 1.7.2