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 ProcessCommand.cpp Source File

ProcessCommand.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 
00030 #include "internal/CommandCommon.h"
00031 
00032 
00033 
00034 /*************************************************************************************************/
00035 WiconnectResult Wiconnect::checkCurrentCommand()
00036 {
00037     WiconnectResult result;
00038 
00039     start:
00040     CHECK_INITIALIZED();
00041     if(!commandExecuting)
00042     {
00043         return WICONNECT_IDLE;
00044     }
00045     CommandContext *context = (CommandContext*)commandContext;
00046 
00047     if(context->commandLen > 0)
00048     {
00049         const TimerTimeout timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs);
00050         const int bytesToWrite = context->commandLen;
00051         const int bytesWritten = serial.write(context->commandPtr, bytesToWrite, timeout);
00052         context->commandPtr += bytesWritten;
00053         context->commandLen -= bytesWritten;
00054         if(bytesToWrite != bytesWritten)
00055         {
00056             if(timeoutTimer.timedOut(context->timeoutMs))
00057             {
00058                 issueCommandCallback(WICONNECT_TIMEOUT);
00059                 return WICONNECT_TIMEOUT;
00060             }
00061             else
00062             {
00063                 return WICONNECT_PROCESSING;
00064             }
00065         }
00066     }
00067 
00068     while(context->reader.isValid())
00069     {
00070         if(context->bytesToWrite == 0)
00071         {
00072             context->responseBufferPtr = context->responseBuffer;
00073             if(WICONNECT_FAILED(result, context->reader.call(context->user, context->responseBuffer, context->responseBufferLen, &context->bytesToWrite)))
00074             {
00075                 issueCommandCallback(result);
00076                 return result;
00077             }
00078             else if(context->bytesToWrite == EOF)
00079             {
00080                 context->reader.setInvalid();
00081                 context->bytesToWrite = 0;
00082                 context->responseBufferPtr = context->responseBuffer;
00083                 break;
00084             }
00085             else
00086             {
00087                 timeoutTimer.reset();
00088             }
00089         }
00090         if(context->bytesToWrite > 0)
00091         {
00092             const TimerTimeout timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs);
00093             const int bytesToWrite = context->bytesToWrite;
00094             const int bytesWritten = serial.write(context->responseBufferPtr, bytesToWrite, timeout);
00095             context->responseBufferPtr += bytesWritten;
00096             context->bytesToWrite -= bytesWritten;
00097             if(bytesToWrite != bytesWritten)
00098             {
00099                 if(timeoutTimer.timedOut(context->timeoutMs))
00100                 {
00101                     issueCommandCallback(WICONNECT_TIMEOUT);
00102                     return WICONNECT_TIMEOUT;
00103                 }
00104                 else
00105                 {
00106                     return WICONNECT_PROCESSING;
00107                 }
00108             }
00109         }
00110     }
00111 
00112     result = receiveResponse();
00113     if(result == WICONNECT_PROCESSING && !context->nonBlocking)
00114     {
00115         goto start;
00116     }
00117     return result;
00118 }
00119 
00120 /*************************************************************************************************/
00121 WiconnectResult Wiconnect::receiveResponse()
00122 {
00123 loop:
00124     WiconnectResult result = receivePacket();
00125 
00126     if(result == WICONNECT_PROCESSING)
00127     {
00128     }
00129     else if(result == WICONNECT_SUCCESS)
00130     {
00131         CommandHeader *header = (CommandHeader*)commandHeaderBuffer;
00132         CommandContext *context = (CommandContext*)commandContext;
00133 
00134         // TODO: need to notify safemode
00135 
00136         if(header->response_type == WICONNECT_CMD_TYPE_REPLY || header->response_type == WICONNECT_CMD_TYPE_SAFEMODE)
00137         {
00138             if(header->response_code != WICONNECT_CMD_SUCCESS)
00139             {
00140                 DEBUG_CMD_ERROR(header->response_code);
00141                 flush();
00142                 issueCommandCallback(WICONNECT_CMD_RESPONSE_ERROR);
00143                 return WICONNECT_CMD_RESPONSE_ERROR;
00144             }
00145             else if(header->response_len > 0)
00146             {
00147                 DEBUG_CMD_RESPONSE(context->responseBuffer);
00148 
00149                 if(header->response_len < (uint16_t)context->responseBufferLen)
00150                 {
00151                     context->responseBuffer[header->response_len] = 0;
00152                 }
00153             }
00154             else
00155             {
00156                 *context->responseBuffer = 0;
00157             }
00158 
00159             issueCommandCallback(WICONNECT_SUCCESS);
00160 
00161             return WICONNECT_SUCCESS;
00162         }
00163         else
00164         {
00165             DEBUG_CMD_LOG(context->responseBuffer);
00166             RESET_CMD_HEADER(header);
00167             context->responseBufferPtr = context->responseBuffer;
00168             goto loop;
00169         }
00170     }
00171     else
00172     {
00173         issueCommandCallback(result);
00174     }
00175 
00176     return result;
00177 }
00178 
00179 /*************************************************************************************************/
00180 WiconnectResult Wiconnect::receivePacket()
00181 {
00182     CommandHeader *header = (CommandHeader*)commandHeaderBuffer;
00183     CommandContext *context = (CommandContext*)commandContext;
00184     if(header->bytes_remaining > 0)
00185     {
00186         uint16_t bytesReceived;
00187         static uint8_t buffer[WICONNECT_HEADER_LENGTH];
00188 
00189         while(header->bytes_remaining > 0)
00190         {
00191             const TimerTimeout timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs);
00192             bytesReceived = serial.read((char*)buffer, header->bytes_remaining, timeout);
00193             if(bytesReceived == 0)
00194             {
00195                 return timeoutTimer.timedOut(context->timeoutMs) ? WICONNECT_TIMEOUT : WICONNECT_PROCESSING;
00196             }
00197 
00198             for(uint8_t *ptr = buffer; bytesReceived > 0; ++ptr)
00199             {
00200                 if(header->response_type == WICONNECT_CMD_TYPE_NULL)
00201                 {
00202                     if( *ptr == WICONNECT_CMD_TYPE_REPLY ||
00203                         *ptr == WICONNECT_CMD_TYPE_LOG ||
00204                         *ptr == WICONNECT_CMD_TYPE_SAFEMODE)
00205                     {
00206                         header->response_type = (ResponseType)*ptr;
00207                         -- header->bytes_remaining;
00208                     }
00209                     --bytesReceived;
00210                 }
00211                 else if(header->response_code == WICONNECT_CMD_CODE_NULL)
00212                 {
00213                     if(*ptr >= '0' && *ptr <= '7')
00214                     {
00215                         header->response_code = (ResponseCode)(*ptr - '0' + 1);
00216                         --header->bytes_remaining;
00217                         header->len_buffer_ptr = header->len_buffer;
00218                     }
00219                     else
00220                     {
00221                         RESET_CMD_HEADER(header);
00222                     }
00223                     --bytesReceived;
00224                 }
00225                 else if(header->bytes_remaining > 2)
00226                 {
00227                     uint8_t len_chars = MIN((int)bytesReceived, (int)(header->bytes_remaining-2));
00228                     header->bytes_remaining -= len_chars;
00229                     bytesReceived -= len_chars;
00230                     while(len_chars-- > 0)
00231                     {
00232                         *header->len_buffer_ptr++ = *ptr++;
00233                     }
00234                     --ptr; // need to decrement since the for loop increments
00235                     if(header->bytes_remaining == 2)
00236                     {
00237                         uint32_t packetLen;
00238                         *header->len_buffer_ptr = 0;
00239                         if(!StringUtil::strToUint32((const char*)header->len_buffer, &packetLen))
00240                         {
00241                             RESET_CMD_HEADER(header);
00242                         }
00243                         else
00244                         {
00245                             if(packetLen > 0)
00246                             {
00247                                 if(packetLen <= 2)
00248                                 {
00249                                     return WICONNECT_CMD_RESPONSE_ERROR;
00250                                 }
00251                                 packetLen -= 2;
00252                             }
00253                             if((int)packetLen > context->responseBufferLen)
00254                             {
00255                                 DEBUG_ERROR("Packet larger than response buffer: %d > %d", packetLen, context->responseBufferLen);
00256                                 return WICONNECT_OVERFLOW;
00257                             }
00258                             header->response_len = (uint16_t)packetLen;
00259                             context->bytesToRead = packetLen;
00260                         }
00261                     }
00262                 }
00263                 else if(header->bytes_remaining == 2)
00264                 {
00265                     --bytesReceived;
00266                     if(*ptr == '\r')
00267                     {
00268                         header->bytes_remaining = 1;
00269                     }
00270                     else
00271                     {
00272                         RESET_CMD_HEADER(header);
00273                     }
00274                 }
00275                 else
00276                 {
00277                     --bytesReceived;
00278                     if(*ptr == '\n')
00279                     {
00280                         header->bytes_remaining = 0;
00281                         break;
00282                     }
00283                     else
00284                     {
00285                         RESET_CMD_HEADER(header);
00286                     }
00287                 }
00288             }
00289         }
00290     }
00291 
00292     while(context->bytesToRead > 0)
00293     {
00294         const TimerTimeout timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs);
00295         const int bytesToRead = context->bytesToRead;
00296         const int bytesReceived = serial.read(context->responseBufferPtr, bytesToRead, timeout);
00297         context->responseBufferPtr += bytesReceived;
00298         context->bytesToRead -= bytesReceived;
00299 
00300         if(bytesReceived != bytesToRead)
00301         {
00302             return timeoutTimer.timedOut(context->timeoutMs) ? WICONNECT_TIMEOUT : WICONNECT_PROCESSING;
00303         }
00304         else if(context->bytesToRead == 0)
00305         {
00306             char buf[2];
00307             int bytesRemaining = 2;
00308             *context->responseBufferPtr = 0;
00309 
00310             // read the trailing \r\n
00311             while(bytesRemaining > 0)
00312             {
00313                 const int bytesReceived = serial.read(buf, bytesRemaining, 0);
00314                 bytesRemaining -= bytesReceived;
00315 
00316                 if(bytesRemaining > 0 && timeoutTimer.timedOut(context->timeoutMs))
00317                 {
00318                     return WICONNECT_TIMEOUT;
00319                 }
00320             }
00321         }
00322     }
00323 
00324     return (header->response_code != WICONNECT_CMD_CODE_NULL &&
00325             header->response_type != WICONNECT_CMD_TYPE_NULL &&
00326             context->bytesToRead == 0) ? WICONNECT_SUCCESS : WICONNECT_PROCESSING;
00327 }
00328 
00329 /*************************************************************************************************/
00330 void Wiconnect::issueCommandCallback(WiconnectResult result)
00331 {
00332     CommandHeader *header = (CommandHeader*)commandHeaderBuffer;
00333     CommandContext *context = (CommandContext*)commandContext;
00334 #ifdef WICONNECT_ASYNC_TIMER_ENABLED
00335     void *returnPtr = (currentQueuedCommand != NULL) ? (void*)currentQueuedCommand : (void*)context->responseBuffer;
00336     currentQueuedCommand = NULL;
00337     commandProcessorTimer.stop();
00338 #else
00339     void *returnPtr = (void*)context->responseBuffer;
00340 #endif
00341 
00342     context->callback.call(result, returnPtr, (void*)(uint32_t)header->response_len);
00343     commandExecuting = false;
00344 
00345 #ifdef WICONNECT_ASYNC_TIMER_ENABLED
00346     processNextQueuedCommand();
00347 #endif
00348 }
00349 
00350 /*************************************************************************************************/
00351 void Wiconnect::stopCurrentCommand()
00352 {
00353     internalProcessingState = 0;
00354     issueCommandCallback(WICONNECT_ABORTED);
00355 }
00356