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
internal/wiconnect/ProcessCommand.cpp
- Committer:
- dan_ackme
- Date:
- 2014-10-23
- Revision:
- 27:b63f5a9cdefa
- Parent:
- 24:e27e23297f02
File content as of revision 27:b63f5a9cdefa:
/** * 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 "CommandCommon.h" /*************************************************************************************************/ WiconnectResult Wiconnect::checkCurrentCommand() { WiconnectResult result; start: CHECK_INITIALIZED(); if(!commandExecuting) { return WICONNECT_IDLE; } CommandContext *context = (CommandContext*)commandContext; if(context->commandLen > 0) { const int timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs); const int bytesToWrite = context->commandLen; const int bytesWritten = serial.write(context->commandPtr, bytesToWrite, timeout); context->commandPtr += bytesWritten; context->commandLen -= bytesWritten; if(bytesToWrite != bytesWritten) { if(timeoutTimer.timedOut(context->timeoutMs)) { issueCommandCallback(WICONNECT_TIMEOUT); return WICONNECT_TIMEOUT; } else { return WICONNECT_PROCESSING; } } } while(context->reader.isValid()) { if(context->bytesToWrite == 0) { context->responseBufferPtr = context->responseBuffer; if(WICONNECT_FAILED(result, context->reader.call(context->user, context->responseBuffer, context->responseBufferLen, &context->bytesToWrite))) { issueCommandCallback(result); return result; } else if(context->bytesToWrite == EOF) { context->reader.setInvalid(); context->bytesToWrite = 0; context->responseBufferPtr = context->responseBuffer; break; } else { timeoutTimer.reset(); } } if(context->bytesToWrite > 0) { const int timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs); const int bytesToWrite = context->bytesToWrite; const int bytesWritten = serial.write(context->responseBufferPtr, bytesToWrite, timeout); context->responseBufferPtr += bytesWritten; context->bytesToWrite -= bytesWritten; if(bytesToWrite != bytesWritten) { if(timeoutTimer.timedOut(context->timeoutMs)) { issueCommandCallback(WICONNECT_TIMEOUT); return WICONNECT_TIMEOUT; } else { return WICONNECT_PROCESSING; } } } } result = receiveResponse(); if(result == WICONNECT_PROCESSING && !context->nonBlocking) { goto start; } return result; } /*************************************************************************************************/ WiconnectResult Wiconnect::receiveResponse() { loop: WiconnectResult result = receivePacket(); if(result == WICONNECT_PROCESSING) { } else if(result == WICONNECT_SUCCESS) { CommandHeader *header = (CommandHeader*)commandHeaderBuffer; CommandContext *context = (CommandContext*)commandContext; // TODO: need to notify safemode if(header->response_type == WICONNECT_CMD_TYPE_REPLY || header->response_type == WICONNECT_CMD_TYPE_SAFEMODE) { if(header->response_code != WICONNECT_CMD_SUCCESS) { DEBUG_CMD_ERROR(header->response_code); flush(); issueCommandCallback(WICONNECT_CMD_RESPONSE_ERROR); return WICONNECT_CMD_RESPONSE_ERROR; } else if(header->response_len > 0) { DEBUG_CMD_RESPONSE(context->responseBuffer); if(header->response_len < context->responseBufferLen) { context->responseBuffer[header->response_len] = 0; } } else { *context->responseBuffer = 0; } issueCommandCallback(WICONNECT_SUCCESS); return WICONNECT_SUCCESS; } else { DEBUG_CMD_LOG(context->responseBuffer); RESET_CMD_HEADER(header); context->responseBufferPtr = context->responseBuffer; goto loop; } } else { issueCommandCallback(result); } return result; } /*************************************************************************************************/ WiconnectResult Wiconnect::receivePacket() { CommandHeader *header = (CommandHeader*)commandHeaderBuffer; CommandContext *context = (CommandContext*)commandContext; if(header->bytes_remaining > 0) { uint16_t bytesReceived; uint8_t buffer[WICONNECT_HEADER_LENGTH]; while(header->bytes_remaining > 0) { const int timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs); bytesReceived = serial.read((char*)buffer, header->bytes_remaining, timeout); if(bytesReceived == 0) { return timeoutTimer.timedOut(context->timeoutMs) ? WICONNECT_TIMEOUT : WICONNECT_PROCESSING; } for(uint8_t *ptr = buffer; bytesReceived > 0; ++ptr) { if(header->response_type == WICONNECT_CMD_TYPE_NULL) { if( *ptr == WICONNECT_CMD_TYPE_REPLY || *ptr == WICONNECT_CMD_TYPE_LOG || *ptr == WICONNECT_CMD_TYPE_SAFEMODE) { header->response_type = (ResponseType)*ptr; -- header->bytes_remaining; } --bytesReceived; } else if(header->response_code == WICONNECT_CMD_CODE_NULL) { if(*ptr >= '0' && *ptr <= '7') { header->response_code = (ResponseCode)(*ptr - '0' + 1); --header->bytes_remaining; header->len_buffer_ptr = header->len_buffer; } else { RESET_CMD_HEADER(header); } --bytesReceived; } else if(header->bytes_remaining > 2) { uint8_t len_chars = MIN((int)bytesReceived, (int)(header->bytes_remaining-2)); header->bytes_remaining -= len_chars; bytesReceived -= len_chars; while(len_chars-- > 0) { *header->len_buffer_ptr++ = *ptr++; } --ptr; // need to decrement since the for loop increments if(header->bytes_remaining == 2) { uint32_t packetLen; *header->len_buffer_ptr = 0; if(!StringUtil::strToUint32((const char*)header->len_buffer, &packetLen)) { RESET_CMD_HEADER(header); } else { if(packetLen > 0) { if(packetLen == 1 || packetLen == 2) { return WICONNECT_CMD_RESPONSE_ERROR; } packetLen -= 2; } if((int)packetLen > context->responseBufferLen) { DEBUG_ERROR("Packet larger than response buffer: %d > %d", packetLen, context->responseBufferLen); return WICONNECT_OVERFLOW; } header->response_len = (uint16_t)packetLen; context->bytesToRead = packetLen; } } } else if(header->bytes_remaining == 2) { --bytesReceived; if(*ptr == '\r') { header->bytes_remaining = 1; } else { RESET_CMD_HEADER(header); } } else { --bytesReceived; if(*ptr == '\n') { header->bytes_remaining = 0; break; } else { RESET_CMD_HEADER(header); } } } } } while(context->bytesToRead > 0) { const int timeout = context->nonBlocking ? 0 : timeoutTimer.remainingMs(context->timeoutMs); const int bytesToRead = context->bytesToRead; const int bytesReceived = serial.read(context->responseBufferPtr, bytesToRead, timeout); context->responseBufferPtr += bytesReceived; context->bytesToRead -= bytesReceived; if(bytesReceived != bytesToRead) { return timeoutTimer.timedOut(context->timeoutMs) ? WICONNECT_TIMEOUT : WICONNECT_PROCESSING; } else if(context->bytesToRead == 0) { *context->responseBufferPtr = 0; // read the trailing \r\n char trailingCRLF[2]; const int bytesReceived = serial.read(trailingCRLF, 2, 100); // FIXME there's a potenital weakness where the trailing \r\n isn't ready to be recieved if(bytesReceived != 2) { return WICONNECT_TIMEOUT; } } } return (header->response_code != WICONNECT_CMD_CODE_NULL && header->response_type != WICONNECT_CMD_TYPE_NULL && context->bytesToRead == 0) ? WICONNECT_SUCCESS : WICONNECT_PROCESSING; } /*************************************************************************************************/ void Wiconnect::issueCommandCallback(WiconnectResult result) { CommandHeader *header = (CommandHeader*)commandHeaderBuffer; CommandContext *context = (CommandContext*)commandContext; #ifdef WICONNECT_ASYNC_TIMER_ENABLED void *returnPtr = (currentQueuedCommand != NULL) ? (void*)currentQueuedCommand : (void*)context->responseBuffer; currentQueuedCommand = NULL; commandProcessorTimer.stop(); #else void *returnPtr = (void*)context->responseBuffer; #endif context->callback.call(result, returnPtr, (void*)(uint32_t)header->response_len); commandExecuting = false; #ifdef WICONNECT_ASYNC_TIMER_ENABLED processNextQueuedCommand(); #endif } /*************************************************************************************************/ void Wiconnect::stopCurrentCommand() { internalProcessingState = 0; issueCommandCallback(WICONNECT_ABORTED); }