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

Wiconnect.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 <stdio.h>
00030 #include <stdarg.h>
00031 #include <string.h>
00032 
00033 #include "api/WiconnectInterface.h"
00034 #include "internal/common.h"
00035 #include "internal/CommandCommon.h"
00036 
00037 
00038 
00039 
00040 using namespace wiconnect;
00041 
00042 
00043 
00044 
00045 
00046 #ifdef WICONNECT_ENABLE_MALLOC
00047 #define MALLOC_ARGS , void* (*mallocPtr)(size_t), void (*freePtr)(void*)
00048 #define MALLOC_CONSTRUCTORS   _malloc(mallocPtr), _free(freePtr),
00049 #else
00050 #define MALLOC_ARGS
00051 #define MALLOC_CONSTRUCTORS
00052 #endif
00053 
00054 
00055 static Wiconnect* instance = NULL;
00056 
00057 
00058 
00059 
00060 /*************************************************************************************************/
00061 void Wiconnect::prepare(void *internalBuffer_, int internalBufferSize_, bool nonBlocking_)
00062 {
00063     instance = this;
00064     internalBufferAlloc = false;
00065 #ifdef WICONNECT_ENABLE_MALLOC
00066     if(internalBufferSize_ > 0 && internalBuffer_ == NULL)
00067     {
00068         wiconnect_assert(this, "Wiconnect(), malloc not defined", _malloc != NULL);
00069         internalBuffer = (char*)_malloc(internalBufferSize_);
00070         internalBufferAlloc = true;
00071     }
00072     else
00073 #endif
00074     {
00075         internalBuffer = (char*)internalBuffer_;
00076     }
00077 
00078     internalProcessingState = 0;
00079     currentCommandId = NULL;
00080     internalBufferSize = internalBufferSize_;;
00081     nonBlocking = nonBlocking_;
00082     commandExecuting = false;
00083     initialized = false;
00084     needUpdate = false;
00085     pinToGpioMapper = NULL;
00086     defaultTimeoutMs = WICONNECT_DEFAULT_TIMEOUT;
00087 
00088     memset(commandContext, 0, sizeof(commandContext));
00089 
00090 #ifdef WICONNECT_ASYNC_TIMER_ENABLED
00091     commandProcessingPeriod = WICONNECT_DEFAULT_COMMAND_PROCESSING_PERIOD;
00092     currentQueuedCommand = NULL;
00093 #endif
00094 }
00095 
00096 
00097 /*************************************************************************************************/
00098 Wiconnect::Wiconnect(const SerialConfig &serialConfig, int internalBufferSize, void *internalBuffer, Pin reset, Pin wake, bool nonBlocking MALLOC_ARGS) :
00099         NetworkInterface(this), SocketInterface(this), FileInterface(this), GhmInterface(this),
00100         MALLOC_CONSTRUCTORS serial(serialConfig, this), resetGpio(reset), wakeGpio(wake)
00101 {
00102 #ifdef WICONNECT_ENABLE_MALLOC
00103     wiconnect_assert(this, "Wiconnect(), bad malloc/free", (mallocPtr == NULL && freePtr == NULL) || (mallocPtr != NULL && freePtr != NULL));
00104 #endif
00105     prepare(internalBuffer, internalBufferSize, nonBlocking);
00106 }
00107 
00108 /*************************************************************************************************/
00109 Wiconnect::Wiconnect(const SerialConfig &serialConfig, Pin reset, Pin wake, bool nonBlocking MALLOC_ARGS) :
00110     NetworkInterface(this), SocketInterface(this), FileInterface(this), GhmInterface(this),
00111     MALLOC_CONSTRUCTORS serial(serialConfig, this), resetGpio(reset), wakeGpio(wake)
00112 {
00113 #ifdef WICONNECT_ENABLE_MALLOC
00114     wiconnect_assert(this, "Wiconnect(), bad malloc/free", (mallocPtr == NULL && freePtr == NULL) || (mallocPtr != NULL && freePtr != NULL));
00115 #endif
00116     prepare(NULL, 0, nonBlocking);
00117 }
00118 
00119 /*************************************************************************************************/
00120 Wiconnect::~Wiconnect()
00121 {
00122 #ifdef WICONNECT_ENABLE_MALLOC
00123     if(internalBufferAlloc)
00124     {
00125         _free(internalBuffer);
00126     }
00127 #endif
00128 }
00129 
00130 /*************************************************************************************************/
00131 WiconnectResult Wiconnect::init(bool bringNetworkUp)
00132 {
00133     WiconnectResult result;
00134     int retries;
00135     bool configuredBus = false;
00136     bool savedNonBlocking = nonBlocking;
00137 
00138     DEBUG_INFO("Initializing wiconnect");
00139 
00140     serial.initialize();
00141 
00142     if(WICONNECT_FAILED(result, reset()))
00143     {
00144         return result;
00145     }
00146 
00147     delayMs(1000);
00148 
00149     initialized = true;
00150     nonBlocking = false;
00151 
00152 
00153     loop:
00154     for(retries = 3; retries > 0; --retries)
00155     {
00156         result = sendCommand(1000, CMD_SET_SYSTEM_COMMAND_MODE, "machine");
00157         if(result != WICONNECT_SUCCESS)
00158         {
00159             delayMs(100);
00160         }
00161         else
00162         {
00163             break;
00164         }
00165     }
00166 
00167     if(result != WICONNECT_SUCCESS && !configuredBus)
00168     {
00169         configuredBus = true;
00170         if(configureModuleDataBus())
00171         {
00172             goto loop;
00173         }
00174     }
00175 
00176     if(result == WICONNECT_SUCCESS)
00177     {
00178         if(WICONNECT_SUCCEEDED(result, getVersion()))
00179         {
00180             const uint32_t version = Wiconnect::wiconnectVersionToInt(this->internalBuffer);
00181             if(version < WICONNECT_MINIMUM_VERSION)
00182             {
00183                 needUpdate = true;
00184                 result = WICONNECT_FIRMWARE_OUTDATED;
00185             }
00186         }
00187     }
00188     if(result == WICONNECT_SUCCESS)
00189     {
00190         sendCommand("set stream.auto_close 0");
00191     }
00192     if(result == WICONNECT_SUCCESS && bringNetworkUp)
00193     {
00194         sendCommand(15000, "ping -g");
00195     }
00196 
00197     nonBlocking = savedNonBlocking;
00198     if(result != WICONNECT_SUCCESS && !needUpdate)
00199     {
00200         initialized = false;
00201     }
00202 
00203 
00204     return result;
00205 }
00206 
00207 /*************************************************************************************************/
00208 void Wiconnect::deinit(void)
00209 {
00210     initialized = false;
00211 }
00212 
00213 /*************************************************************************************************/
00214 Wiconnect* Wiconnect::getInstance()
00215 {
00216     return instance;
00217 }
00218 
00219 /*************************************************************************************************/
00220 bool Wiconnect::isInitialized()
00221 {
00222     return initialized;
00223 }
00224 
00225 /*************************************************************************************************/
00226 bool Wiconnect::updateRequired()
00227 {
00228     return needUpdate;
00229 }
00230 
00231 /*************************************************************************************************/
00232 WiconnectResult Wiconnect::reset()
00233 {
00234     resetGpio = 0;
00235     delayMs(10);
00236     resetGpio = 1;
00237     delayMs(1000);
00238     return WICONNECT_SUCCESS;
00239 }
00240 
00241 /*************************************************************************************************/
00242 WiconnectResult Wiconnect::wakeup()
00243 {
00244     wakeGpio = 1;
00245     delayMs(1);
00246     wakeGpio = 0;
00247     return WICONNECT_SUCCESS;
00248 }
00249 
00250 /*************************************************************************************************/
00251 void Wiconnect::flush(int delayMs)
00252 {
00253     if(delayMs != 0)
00254     {
00255         serial.write("\r\n\r\n", 4, 0);
00256     }
00257     delayMs(delayMs);
00258     serial.flush();
00259 }
00260 
00261 /*************************************************************************************************/
00262 void Wiconnect::setPinToGpioMapper(PinToGpioMapper mapper)
00263 {
00264     pinToGpioMapper = mapper;
00265 }
00266 
00267 /*************************************************************************************************/
00268 WiconnectResult Wiconnect::getVersion(char *versionBuffer, int versionBufferSize, const Callback &completeCallback)
00269 {
00270     WiconnectResult result;
00271 
00272     if(versionBuffer != NULL && versionBufferSize == 0)
00273     {
00274         return WICONNECT_BAD_ARG;
00275     }
00276 
00277     _CHECK_OTHER_COMMAND_EXECUTING();
00278 
00279     if(versionBuffer == NULL)
00280     {
00281         result = sendCommand(completeCallback, CMD_GET_VERSION);
00282     }
00283     else
00284     {
00285         result = sendCommand(completeCallback, versionBuffer, versionBufferSize, CMD_GET_VERSION);
00286     }
00287 
00288     _CHECK_CLEANUP_COMMAND();
00289 
00290     return result;
00291 }
00292 
00293 /*************************************************************************************************/
00294 WiconnectResult Wiconnect::updateFirmware(bool forced, const char *versionStr, const Callback &completeCallback)
00295 {
00296     WiconnectResult result;
00297     char *cmdBuffer = internalBuffer;
00298 
00299     if(_WICONNECT_IS_IDLE())
00300     {
00301         strcpy(cmdBuffer, "ota ");
00302         if(versionStr != NULL)
00303         {
00304             strcat(cmdBuffer, "-b wiconnect-");
00305             strcat(cmdBuffer, versionStr);
00306         }
00307         else if(forced)
00308         {
00309             strcat(cmdBuffer, "-f");
00310         }
00311     }
00312 
00313     _CHECK_OTHER_COMMAND_EXECUTING();
00314 
00315     result = sendCommand(completeCallback, WICONNECT_FIRMWARE_UPDATE_TIMEOUT, cmdBuffer);
00316 
00317     _CHECK_CLEANUP_COMMAND();
00318 
00319     return result;
00320 }
00321 
00322 /*************************************************************************************************/
00323 const char* Wiconnect::getWiconnectResultStr(WiconnectResult wiconnectResult)
00324 {
00325     static const char* const wiconnectSuccessStrTable[] = {
00326             "Success",                              // WICONNECT_SUCCESS
00327             "Processing command",                   // WICONNECT_PROCESSING
00328             "Idle",                                 // WICONNECT_IDLE
00329             "Aborted",                              // WICONNECT_ABORTED
00330     };
00331     static const char* const wiconnectErrorStrTable[] = {
00332             "",
00333             "General error",                        // WICONNECT_ERROR
00334             "WiConnect command code error",         // WICONNECT_CMD_RESPONSE_ERROR
00335             "Null buffer",                          // WICONNECT_NULL_BUFFER
00336             "Not initialized",                      // WICONNECT_NOT_INITIALIZED
00337             "Overflow",                             // WICONNECT_OVERFLOW
00338             "Timeout",                              // WICONNECT_TIMEOUT
00339             "Response handler null",                // WICONNECT_RESPONSE_HANDLER_NULL
00340             "Response parse error",                 // WICONNECT_RESPONSE_PARSE_ERROR
00341             "Another command is executing",         // WICONNECT_ANOTHER_CMD_EXECUTING
00342             "Bad argument(s)",                      // WICONNECT_BAD_ARG
00343             "Unsupported",                          // WICONNECT_UNSUPPORTED
00344             "Pin name to GPIO mapper null",         // WICONNECT_PINNAME_TO_GPIO_MAPPER_NULL
00345             "Duplicate",                            // WICONNECT_DUPLICATE
00346             "Not found",                            // WICONNECT_NOT_FOUND
00347             "No mapping for pinname to GPIO",       // WICONNECT_PINNAME_TO_GPIO_NO_MAPPING
00348             "Not connected",                        // WICONNECT_NOT_CONNECTED
00349             "Underflow",                            // WICONNECT_UNDERFLOW
00350             "A monitor is not available",           // WICONNECT_MONITOR_NOT_AVAILABLE
00351             "Not opened for reading",               // WICONNECT_NOT_OPENED_FOR_READING
00352             "WiFi firmware update required",        // WICONNECT_FIRMWARE_OUTDATED
00353     };
00354 
00355     if((int)wiconnectResult >= (int)WICONNECT_SUCCESS)
00356     {
00357         return wiconnectSuccessStrTable[wiconnectResult];
00358     }
00359     else
00360     {
00361         wiconnectResult = (WiconnectResult)(-((int)wiconnectResult));
00362         return wiconnectErrorStrTable[wiconnectResult];
00363     }
00364 }
00365 
00366 /*************************************************************************************************/
00367 uint32_t Wiconnect::wiconnectVersionToInt(char *versionStr)
00368 {
00369     char *idx = strchr(versionStr, ',');
00370     if(idx == NULL)
00371     {
00372         return UINT_MAX;
00373     }
00374     *idx = 0;
00375     idx = versionStr;
00376     while((idx = strchr(versionStr, '-')) != NULL)
00377     {
00378         versionStr = idx + 1;
00379     }
00380 
00381     uint32_t ver;
00382 
00383     if(Wiconnect::fileVersionStrToInt(versionStr, &ver))
00384     {
00385         return ver;
00386     }
00387 
00388     return UINT_MAX;
00389 }
00390 
00391 /*************************************************************************************************/
00392 void Wiconnect::setDebugLogger(LogFunc logFunc)
00393 {
00394 #ifdef WICONNECT_ENABLE_DEBUGGING
00395     debugLogger = logFunc;
00396 #endif
00397 }
00398 
00399 /*************************************************************************************************/
00400 void Wiconnect::setAssertLogger(LogFunc assertLogFunc)
00401 {
00402     assertLogger = assertLogFunc;
00403 }
00404 
00405 #ifdef WICONNECT_ENABLE_DEBUGGING
00406 /*************************************************************************************************/
00407 void Wiconnect::debugLog(const char *msg, ...)
00408 {
00409     if(!debugLogger.isValid())
00410     {
00411         return;
00412     }
00413 
00414     static char buffer[96];
00415     va_list args;
00416     va_start(args, msg);
00417     int len = vsnprintf(buffer, sizeof(buffer)-1, msg, args);
00418     va_end(args);
00419 
00420     if(len > (int)(sizeof(buffer)-6))
00421     {
00422         char *p = &buffer[sizeof(buffer)-6];
00423         *p++ = '.';
00424         *p++ = '.';
00425         *p++ = '.';
00426         *p++ = '\r';
00427         *p++ = '\n';
00428         *p = 0;
00429     }
00430     else
00431     {
00432         if(buffer[len-2] != '\r')
00433         {
00434             char *p = &buffer[len];
00435             *p++ = '\r';
00436             *p++ = '\n';
00437             *p = 0;
00438         }
00439     }
00440     debugLogger.call(buffer);
00441 }
00442 #endif