Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: DHT WIZnetInterface mbed-src
thinger.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_H 00025 #define THINGER_H 00026 00027 #include "pson.h" 00028 #include "thinger_map.hpp" 00029 #include "thinger_resource.hpp" 00030 #include "thinger_message.hpp" 00031 #include "thinger_encoder.hpp" 00032 #include "thinger_decoder.hpp" 00033 #include "thinger_message.hpp" 00034 #include "thinger_io.hpp" 00035 00036 #define KEEP_ALIVE_MILLIS 60000 00037 00038 namespace thinger{ 00039 00040 using namespace protoson; 00041 00042 class thinger : public thinger_io{ 00043 public: 00044 thinger() : 00045 encoder(*this), 00046 decoder(*this), 00047 last_keep_alive(0), 00048 keep_alive_response(true) 00049 { 00050 } 00051 00052 virtual ~thinger(){ 00053 } 00054 00055 private: 00056 thinger_write_encoder encoder; 00057 thinger_read_decoder decoder; 00058 unsigned long last_keep_alive; 00059 bool keep_alive_response; 00060 thinger_map<thinger_resource> resources_; 00061 00062 protected: 00063 /** 00064 * Can be override to start reconnection process 00065 */ 00066 virtual void disconnected(){} 00067 00068 public: 00069 00070 thinger_resource & operator[](const char* res){ 00071 return resources_[res]; 00072 } 00073 00074 bool connect(const char* username, const char* device_id, const char* credential) 00075 { 00076 // reset keep alive status for each connection 00077 keep_alive_response = true; 00078 00079 thinger_message message; 00080 message.resources().add("login").add(username).add(device_id).add(credential); 00081 if(!send_message(message)) return false; 00082 00083 thinger_message response; 00084 return read_message(response) && response.get_signal_flag() == thinger_message::REQUEST_OK; 00085 } 00086 00087 bool call_endpoint(const char* endpoint_name){ 00088 thinger_message message; 00089 message.resources().add("ep").add(endpoint_name); 00090 return send_message(message); 00091 } 00092 00093 bool call_endpoint(const char* endpoint_name, pson& data){ 00094 thinger_message message; 00095 message.set_data(data); 00096 message.resources().add("ep").add(endpoint_name); 00097 return send_message(message); 00098 } 00099 00100 bool send_message(thinger_message& message) 00101 { 00102 thinger_encoder sink; 00103 sink.encode(message); 00104 encoder.pb_encode_varint(message.get_message_type()); 00105 encoder.pb_encode_varint(sink.bytes_written()); 00106 encoder.encode(message); 00107 return write(NULL, 0, true); 00108 } 00109 00110 void handle(unsigned long current_time, bool bytes_available) 00111 { 00112 // handle input 00113 if(bytes_available){ 00114 handle_input(); 00115 } 00116 00117 // handle keep alive 00118 if(current_time-last_keep_alive>KEEP_ALIVE_MILLIS){ 00119 if(keep_alive_response){ 00120 last_keep_alive = current_time; 00121 keep_alive_response = false; 00122 encoder.pb_encode_varint(thinger_message::KEEP_ALIVE); 00123 encoder.pb_encode_varint(0); 00124 write(NULL, 0, true); 00125 }else{ 00126 disconnected(); 00127 } 00128 } 00129 } 00130 00131 bool read_message(thinger_message& message){ 00132 uint8_t message_type = decoder.pb_decode_varint32(); 00133 switch (message_type){ 00134 case thinger_message::MESSAGE: { 00135 size_t size = decoder.pb_decode_varint32(); 00136 decoder.decode(message, size); 00137 } 00138 break; 00139 case thinger_message::KEEP_ALIVE: { 00140 size_t size = decoder.pb_decode_varint32(); 00141 keep_alive_response = true; 00142 } 00143 return false; 00144 default: 00145 return false; 00146 } 00147 return true; 00148 } 00149 00150 bool handle_input(){ 00151 thinger_message message; 00152 if(read_message(message)){ 00153 handle_request_received(message); 00154 } 00155 return true; 00156 } 00157 00158 private: 00159 00160 void handle_request_received(thinger_message& request) 00161 { 00162 thinger_message response(request); 00163 if(!request.has_resource()){ 00164 response.set_signal_flag(thinger_message::REQUEST_ERROR); 00165 } 00166 else{ 00167 thinger_resource * thing_resource = NULL; 00168 for(pson_array::iterator it = request.resources().begin(); it.valid(); it.next()){ 00169 if(!it.item().is_string()){ 00170 response.set_signal_flag(thinger_message::REQUEST_ERROR); 00171 break; 00172 } 00173 const char* resource = it.item(); 00174 00175 if(it.has_next()){ 00176 thing_resource = thing_resource == NULL ? resources_.find(resource) : thing_resource->find(resource); 00177 if(thing_resource==NULL) { 00178 response.set_signal_flag(thinger_message::REQUEST_ERROR); 00179 break; 00180 } 00181 }else{ 00182 if(strcmp("api", resource)==0){ 00183 if(thing_resource==NULL){ 00184 thinger_map<thinger_resource>::entry* current = resources_.begin(); 00185 while(current!=NULL){ 00186 current->value_.fill_api(response.get_data()[current->key_]); 00187 current = current->next_; 00188 } 00189 }else{ 00190 thing_resource->fill_api_io(response.get_data()); 00191 } 00192 }else{ 00193 thing_resource = thing_resource == NULL ? resources_.find(resource) : thing_resource->find(resource); 00194 if(thing_resource==NULL){ 00195 response.set_signal_flag(thinger_message::REQUEST_ERROR); 00196 }else{ 00197 thing_resource->handle_request(request, response); 00198 } 00199 } 00200 } 00201 } 00202 } 00203 send_message(response); 00204 } 00205 }; 00206 } 00207 00208 #endif
Generated on Wed Jul 13 2022 02:25:39 by
