Midnight Cow / ThingerIO

Dependencies:   DHT WIZnetInterface mbed-src

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ThingerMBedClient.h Source File

ThingerMBedClient.h

00001 // The MIT License (MIT)
00002 //
00003 // Copyright (c) 2015 THINGER LTD
00004 // Author: alvarolb@gmail.com (Alvaro Luis Bustamante)
00005 //
00006 // Permission is hereby granted, free of charge, to any person obtaining a copy
00007 // of this software and associated documentation files (the "Software"), to deal
00008 // in the Software without restriction, including without limitation the rights
00009 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010 // copies of the Software, and to permit persons to whom the Software is
00011 // furnished to do so, subject to the following conditions:
00012 //
00013 // The above copyright notice and this permission notice shall be included in
00014 // all copies or substantial portions of the Software.
00015 //
00016 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00019 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00020 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00021 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00022 // THE SOFTWARE.
00023 
00024 #ifndef THINGER_MBED_CLIENT_H
00025 #define THINGER_MBED_CLIENT_H
00026 
00027 #include "thinger/thinger.h"
00028 
00029 //#define _DEBUG_
00030 
00031 using namespace protoson;
00032 
00033 dynamic_memory_allocator alloc;
00034 //circular_memory_allocator<512> alloc;
00035 memory_allocator& protoson::pool = alloc;
00036 
00037 #define THINGER_SERVER "iot.thinger.io"
00038 #define THINGER_PORT 25200
00039 #define RECONNECTION_TIMEOUT 5000 // milliseconds
00040 
00041 //---For MBED---//
00042 
00043 #ifndef Client
00044     #define Client              TCPSocketConnectionArdu
00045 #endif
00046 
00047 #ifndef millis
00048     #define millis()        us_ticker_read()/1000
00049 #endif
00050 
00051 #ifndef delay    
00052     #define delay               wait_ms
00053 #endif    
00054 
00055 
00056 class ThingerClient : public thinger::thinger {
00057 
00058 
00059 public:
00060     ThingerClient(Client& client, const char* user, const char* device, const char* device_credential) :
00061             client_(client), username_(user), device_id_(device), device_password_(device_credential),
00062             temp_data_(NULL), out_size_(0)
00063     {
00064 
00065     }
00066 
00067     ~ThingerClient()
00068     {
00069 
00070     }
00071 
00072 protected:
00073 
00074     virtual bool read(char* buffer, size_t size)
00075     {
00076         size_t total_read = 0;
00077         while(total_read<size){
00078             int read = client_.readBytes((uint8_t*)buffer, size-total_read);
00079             if(read<0) return false;
00080             total_read += read;
00081         }
00082         return total_read == size;
00083     }
00084 
00085     // TODO Allow removing this Nagle's algorithm implementation if the underlying device already implements it
00086     virtual bool write(const char* buffer, size_t size, bool flush=false){
00087         if(size>0){
00088             temp_data_ = (uint8_t*) realloc(temp_data_, out_size_ + size);
00089             memcpy(&temp_data_[out_size_], buffer, size);
00090             out_size_ += size;
00091         }
00092         if(flush && out_size_>0){
00093             #ifdef _DEBUG_
00094             printf("[THINGER] Writing bytes: %d", out_size_);
00095             #endif
00096 
00097             size_t written = client_.write(temp_data_, out_size_);
00098             bool success = written == out_size_;
00099             free(temp_data_);
00100             temp_data_ = NULL;
00101             out_size_ = 0;
00102 
00103             #ifdef _DEBUG_
00104             printf(" [%s]\r\n",success ? "OK" : "FAIL");
00105             #endif
00106 
00107             //FIXME Without this small delay or activating the debug (which takes time), the CC3200 does not work well. Why?
00108             #ifdef __CC3200R1M1RGC__
00109             delay(1);
00110             #endif
00111             return success;
00112         }
00113         return true;
00114     }
00115 
00116     virtual void disconnected(){
00117         thinger_state_listener(SOCKET_TIMEOUT);
00118         client_.stop();
00119         thinger_state_listener(SOCKET_DISCONNECTED);
00120     }
00121 
00122     virtual bool connect_network(){
00123         return true;
00124     }
00125 
00126     virtual bool network_connected(){
00127         return true;
00128     }
00129 
00130     enum THINGER_STATE{
00131         NETWORK_CONNECTING,
00132         NETWORK_CONNECTED,
00133         NETWORK_CONNECT_ERROR,
00134         SOCKET_CONNECTING,
00135         SOCKET_CONNECTED,
00136         SOCKET_CONNECTION_ERROR,
00137         SOCKET_DISCONNECTED,
00138         SOCKET_TIMEOUT,
00139         THINGER_AUTHENTICATING,
00140         THINGER_AUTHENTICATED,
00141         THINGER_AUTH_FAILED
00142     };
00143 
00144     virtual void thinger_state_listener(THINGER_STATE state){
00145         #ifdef _DEBUG_
00146         switch(state){
00147             case NETWORK_CONNECTING:
00148                 printf("[NETWORK] Starting connection...\r\n");
00149                 break;
00150             case NETWORK_CONNECTED:
00151                 printf("[NETWORK] Connected!\r\n");
00152                 break;
00153             case NETWORK_CONNECT_ERROR:
00154                 printf("[NETWORK] Cannot connect!\r\n");
00155                 break;
00156             case SOCKET_CONNECTING:
00157                 printf("[_SOCKET] Connecting to %s : %d ...", THINGER_SERVER,THINGER_PORT);                
00158                 break;
00159             case SOCKET_CONNECTED:
00160                 printf("[_SOCKET] Connected!\r\n");
00161                 break;
00162             case SOCKET_CONNECTION_ERROR:
00163                 printf("[_SOCKET] Error while connecting!\r\n");
00164                 break;
00165             case SOCKET_DISCONNECTED:
00166                 printf("[_SOCKET] Is now closed!\r\n");
00167                 break;
00168             case SOCKET_TIMEOUT:
00169                 printf("[_SOCKET] Timeout!\r\n");
00170                 break;
00171             case THINGER_AUTHENTICATING:
00172                 printf("[THINGER] Authenticating. User: %s Device: %s\r\n",username_,device_id_);
00173                 break;
00174             case THINGER_AUTHENTICATED:
00175                 printf("[THINGER] Authenticated!\r\n");
00176                 break;
00177             case THINGER_AUTH_FAILED:
00178                 printf("[THINGER] Auth Failed! Check username, device id, or device credentials.\r\n");
00179                 break;
00180         }
00181         #endif
00182     }
00183 
00184     bool handle_connection()
00185     {
00186         bool network = network_connected();
00187 
00188         if(!network){
00189             thinger_state_listener(NETWORK_CONNECTING);
00190             network = connect_network();
00191             if(!network){
00192                 thinger_state_listener(NETWORK_CONNECT_ERROR);
00193                 return false;
00194             }
00195             thinger_state_listener(NETWORK_CONNECTED);
00196         }
00197 
00198         bool client = client_.connected();
00199         if(!client){
00200             client = connect_client();
00201             if(!client){
00202                 return false;
00203             }
00204         }
00205         return network && client;
00206     }
00207 
00208     bool connect_client(){
00209         bool connected = false;
00210         client_.stop(); // cleanup previous socket
00211         thinger_state_listener(SOCKET_CONNECTING);
00212         if (client_.connect(THINGER_SERVER, THINGER_PORT) == 0) {
00213             delay(3000);
00214             thinger_state_listener(SOCKET_CONNECTED);
00215             thinger_state_listener(THINGER_AUTHENTICATING);
00216             connected = thinger::thinger::connect(username_, device_id_, device_password_);
00217             if(!connected){
00218                 thinger_state_listener(THINGER_AUTH_FAILED);
00219                 client_.stop();
00220                 thinger_state_listener(SOCKET_DISCONNECTED);
00221             }
00222             else{
00223                 thinger_state_listener(THINGER_AUTHENTICATED);
00224             }
00225         }
00226         else{
00227             thinger_state_listener(SOCKET_CONNECTION_ERROR);
00228         }
00229         return connected;
00230     }
00231 
00232 public:
00233 
00234     void handle(){
00235         if(handle_connection()){
00236             #ifdef _DEBUG_
00237             if(client_.available()>0){
00238                 printf("[THINGER] Available bytes: %d", client_.available());
00239             }
00240             #endif
00241             thinger::thinger::handle(millis(), client_.available()>0);
00242         }else{
00243             delay(RECONNECTION_TIMEOUT); // get some delay for a connection retry
00244         }
00245     }
00246 
00247 private:
00248 
00249     Client& client_;
00250     const char* username_;
00251     const char* device_id_;
00252     const char* device_password_;
00253     uint8_t * temp_data_;
00254     size_t out_size_;
00255 };
00256 
00257 #endif