* AM2321的取温度间隔得大于2s,否则,i2c会不工作了 * SimpleTimer有个bug,会导致两次快速的读温度,现在读温度函数里加了保护 * Blynk有个bug,会导致无法把数据传到服务器 * 现在可以正常工作了

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BlynkProtocol.h Source File

BlynkProtocol.h

Go to the documentation of this file.
00001 /**
00002  * @file       BlynkProtocol.h
00003  * @author     Volodymyr Shymanskyy
00004  * @license    This project is released under the MIT License (MIT)
00005  * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
00006  * @date       Jan 2015
00007  * @brief      Blynk protocol implementation
00008  *
00009  */
00010 
00011 #ifndef BlynkProtocol_h
00012 #define BlynkProtocol_h
00013 
00014 #include <string.h>
00015 #include <stdlib.h>
00016 #include <Blynk/BlynkDebug.h>
00017 #include <Blynk/BlynkProtocolDefs.h>
00018 #include <Blynk/BlynkApi.h>
00019 #include <utility/BlynkUtility.h>
00020 
00021 template <class Transp>
00022 class BlynkProtocol
00023     : public BlynkApi< BlynkProtocol<Transp> >
00024 {
00025     friend class BlynkApi< BlynkProtocol<Transp> >;
00026 public:
00027     enum BlynkState {
00028         CONNECTING,
00029         CONNECTED,
00030         DISCONNECTED,
00031     };
00032 
00033     BlynkProtocol(Transp& transp)
00034         : conn(transp)
00035         , authkey(NULL)
00036         , lastActivityIn(0)
00037         , lastActivityOut(0)
00038         , lastHeartbeat(0)
00039 #ifdef BLYNK_MSG_LIMIT
00040         , deltaCmd(0)
00041 #endif
00042         , currentMsgId(0)
00043         , state(CONNECTING)
00044     {}
00045 
00046     bool connected () {
00047         LOG_ENTER;
00048         return state == CONNECTED;
00049     }
00050 
00051     bool connect(uint32_t timeout = BLYNK_TIMEOUT_MS*3) {
00052         LOG_ENTER;
00053         conn.disconnect();
00054         state = CONNECTING;
00055         millis_time_t started = this->getMillis();
00056         while ((state != CONNECTED) &&
00057                 (this->getMillis() - started < timeout)) {
00058             run();
00059         }
00060         return state == CONNECTED;
00061     }
00062 
00063     void disconnect() {
00064         LOG_ENTER;
00065         conn.disconnect();
00066         state = DISCONNECTED;
00067         BLYNK_LOG1(BLYNK_F("Disconnected"));
00068     }
00069 
00070     bool run(bool avail = false);
00071 
00072     // TODO: Fixme
00073     void startSession() {
00074         LOG_ENTER;
00075         conn.connect();
00076         state = CONNECTING;
00077 #ifdef BLYNK_MSG_LIMIT
00078         deltaCmd = 1000;
00079 #endif
00080         currentMsgId = 0;
00081         lastHeartbeat = lastActivityIn = lastActivityOut = this->getMillis(); // TODO: - 5005UL
00082     }
00083 
00084     void sendCmd(uint8_t cmd, uint16_t id = 0, const void* data = NULL, size_t length = 0, const void* data2 = NULL, size_t length2 = 0);
00085 
00086 private:
00087     int readHeader(BlynkHeader& hdr);
00088     uint16_t getNextMsgId();
00089 
00090 protected:
00091     void begin(const char* auth) {
00092         BLYNK_LOG1(BLYNK_F("Blynk v" BLYNK_VERSION " on " BLYNK_INFO_DEVICE));
00093         this->authkey = auth;
00094     }
00095     bool processInput(void);
00096 
00097     Transp& conn;
00098 
00099 private:
00100     const char* authkey;
00101     millis_time_t lastActivityIn;
00102     millis_time_t lastActivityOut;
00103     union {
00104         millis_time_t lastHeartbeat;
00105         millis_time_t lastLogin;
00106     };
00107 #ifdef BLYNK_MSG_LIMIT
00108     millis_time_t deltaCmd;
00109 #endif
00110     uint16_t currentMsgId;
00111 protected:
00112     BlynkState state;
00113 };
00114 
00115 template <class Transp>
00116 bool BlynkProtocol<Transp>::run(bool avail)
00117 {
00118     //LOG_ENTER;
00119 #if !defined(BLYNK_NO_YIELD)
00120 asdf
00121     yield();
00122 #endif
00123 
00124     if (state == DISCONNECTED) {
00125         return false;
00126     }
00127 
00128     const bool tconn = conn.connected();
00129 
00130     if (tconn) {
00131         if (avail || conn.available() > 0) {
00132             //BLYNK_LOG2(BLYNK_F("Available: "), conn.available());
00133             //const unsigned long t = micros();
00134             if (!processInput()) {
00135                 conn.disconnect();
00136 // TODO: Only when in direct mode?
00137 #ifdef BLYNK_USE_DIRECT_CONNECT
00138                 state = CONNECTING;
00139 #endif
00140                 //BlynkOnDisconnected();
00141                 return false;
00142             }
00143             //BLYNK_LOG2(BLYNK_F("Proc time: "), micros() - t);
00144         }
00145     }
00146 
00147     const millis_time_t t = this->getMillis();
00148 
00149     if (state == CONNECTED) {
00150         if (!tconn) {
00151             state = CONNECTING;
00152             lastHeartbeat = t;
00153             //BlynkOnDisconnected();
00154             return false;
00155         }
00156 
00157         if (t - lastActivityIn > (1000UL * BLYNK_HEARTBEAT + BLYNK_TIMEOUT_MS*3)) {
00158 #ifdef BLYNK_DEBUG
00159             BLYNK_LOG6(BLYNK_F("Heartbeat timeout: "), t, BLYNK_F(", "), lastActivityIn, BLYNK_F(", "), lastHeartbeat);
00160 #else
00161             BLYNK_LOG1(BLYNK_F("Heartbeat timeout"));
00162 #endif
00163             conn.disconnect();
00164             state = CONNECTING;
00165             //BlynkOnDisconnected();
00166             return false;
00167         } else if ((t - lastActivityIn  > 1000UL * BLYNK_HEARTBEAT ||
00168                     t - lastActivityOut > 1000UL * BLYNK_HEARTBEAT) &&
00169                    t - lastHeartbeat   > BLYNK_TIMEOUT_MS) {
00170             // Send ping if we didn't either send or receive something
00171             // for BLYNK_HEARTBEAT seconds
00172             sendCmd(BLYNK_CMD_PING);
00173             lastHeartbeat = t;
00174         }
00175 #ifndef BLYNK_USE_DIRECT_CONNECT
00176     } else if (state == CONNECTING) {
00177         if (tconn && (t - lastLogin > BLYNK_TIMEOUT_MS)) {
00178             BLYNK_LOG1(BLYNK_F("Login timeout"));
00179             conn.disconnect();
00180             state = CONNECTING;
00181             return false;
00182         } else if (!tconn && (t - lastLogin > 5000UL)) {
00183             conn.disconnect();
00184             if (!conn.connect()) {
00185                 lastLogin = t;
00186                 return false;
00187             }
00188 
00189 #ifdef BLYNK_MSG_LIMIT
00190             deltaCmd = 1000;
00191 #endif
00192             sendCmd(BLYNK_CMD_LOGIN, 1, authkey, strlen(authkey));
00193             lastLogin = lastActivityOut;
00194             return true;
00195         }
00196 #else
00197     } else if (state == CONNECTING) {
00198         if (!tconn)
00199             conn.connect();
00200 #endif
00201     }
00202     return true;
00203 }
00204 
00205 template <class Transp>
00206 BLYNK_FORCE_INLINE
00207 bool BlynkProtocol<Transp>::processInput(void)
00208 {
00209     BlynkHeader hdr;
00210     const int ret = readHeader(hdr);
00211 
00212     if (ret == 0) {
00213         return true; // Considered OK (no data on input)
00214     }
00215 
00216     if (ret < 0 || hdr.msg_id == 0) {
00217 #ifdef BLYNK_DEBUG
00218         BLYNK_LOG2(BLYNK_F("Bad hdr len: "), ret);
00219 #endif
00220         return false;
00221     }
00222 
00223     if (hdr.type == BLYNK_CMD_RESPONSE) {
00224         lastActivityIn = this->getMillis();
00225 
00226 #ifndef BLYNK_USE_DIRECT_CONNECT
00227         if (state == CONNECTING && (1 == hdr.msg_id)) {
00228             switch (hdr.length) {
00229                 case BLYNK_SUCCESS:
00230                 case BLYNK_ALREADY_LOGGED_IN:
00231                     BLYNK_LOG3(BLYNK_F("Ready (ping: "), lastActivityIn-lastHeartbeat, BLYNK_F("ms)."));
00232                     lastHeartbeat = lastActivityIn;
00233                     state = CONNECTED;
00234                     this->sendInfo();
00235 #if !defined(BLYNK_NO_YIELD)
00236                     yield();
00237 #endif
00238                     BlynkOnConnected();
00239                     return true;
00240                 case BLYNK_INVALID_TOKEN:
00241                     BLYNK_LOG1(BLYNK_F("Invalid auth token"));
00242                     break;
00243                 default:
00244                     BLYNK_LOG2(BLYNK_F("Connect failed. code: "), hdr.length);
00245             }
00246             return false;
00247         }
00248         if (BLYNK_NOT_AUTHENTICATED == hdr.length) {
00249             return false;
00250         }
00251 #endif
00252         // TODO: return code may indicate App presence
00253         return true;
00254     }
00255 
00256     if (hdr.length > BLYNK_MAX_READBYTES) {
00257 #ifdef BLYNK_DEBUG
00258         BLYNK_LOG2(BLYNK_F("Packet too big: "), hdr.length);
00259 #endif
00260         // TODO: Flush
00261         conn.connect();
00262         return true;
00263     }
00264 
00265     uint8_t inputBuffer[hdr.length+1]; // Add 1 to zero-terminate
00266     if (hdr.length != conn.read(inputBuffer, hdr.length)) {
00267 #ifdef DEBUG
00268         BLYNK_LOG1(BLYNK_F("Can't read body"));
00269 #endif
00270         return false;
00271     }
00272     inputBuffer[hdr.length] = '\0';
00273 
00274     BLYNK_DBG_DUMP(">", inputBuffer, hdr.length);
00275 
00276     lastActivityIn = this->getMillis();
00277 
00278     switch (hdr.type) {
00279         case BLYNK_CMD_LOGIN: {
00280 #ifdef BLYNK_USE_DIRECT_CONNECT
00281             if (!strncmp(authkey, (char*)inputBuffer, 32)) {
00282                 BLYNK_LOG1(BLYNK_F("Ready"));
00283                 state = CONNECTED;
00284                 sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_SUCCESS);
00285                 this->sendInfo();
00286             } else {
00287                 BLYNK_LOG1(BLYNK_F("Invalid token"));
00288                 sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_INVALID_TOKEN);
00289             }
00290 #else
00291             BLYNK_LOG1(BLYNK_F("Ready"));
00292             state = CONNECTED;
00293             sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_SUCCESS);
00294             this->sendInfo();
00295 #endif
00296         }
00297         break;
00298         case BLYNK_CMD_PING: {
00299             sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_SUCCESS);
00300         }
00301         break;
00302         case BLYNK_CMD_HARDWARE:
00303         case BLYNK_CMD_BRIDGE: {
00304             currentMsgId = hdr.msg_id;
00305             this->processCmd(inputBuffer, hdr.length);
00306             currentMsgId = 0;
00307         }
00308         break;
00309         default: {
00310 #ifdef BLYNK_DEBUG
00311             BLYNK_LOG2(BLYNK_F("Invalid header type: "), hdr.type);
00312 #endif
00313             // TODO: Flush
00314             conn.connect();
00315         }
00316         break;
00317     }
00318 
00319     return true;
00320 }
00321 
00322 template <class Transp>
00323 int BlynkProtocol<Transp>::readHeader(BlynkHeader& hdr)
00324 {
00325     size_t rlen = conn.read(&hdr, sizeof(hdr));
00326     if (rlen == 0) {
00327         return 0;
00328     }
00329 
00330     if (sizeof(hdr) != rlen) {
00331         return -1;
00332     }
00333 
00334     BLYNK_DBG_DUMP(">", &hdr, sizeof(BlynkHeader));
00335 
00336     hdr.msg_id = ntohs(hdr.msg_id);
00337     hdr.length = ntohs(hdr.length);
00338 
00339     return rlen;
00340 }
00341 
00342 #ifndef BLYNK_SEND_THROTTLE
00343 #define BLYNK_SEND_THROTTLE 10
00344 #endif
00345 
00346 #ifndef BLYNK_SEND_CHUNK
00347 #define BLYNK_SEND_CHUNK 1024 // Just a big number
00348 #endif
00349 
00350 template <class Transp>
00351 void BlynkProtocol<Transp>::sendCmd(uint8_t cmd, uint16_t id, const void* data, size_t length, const void* data2, size_t length2)
00352 {
00353     //pc.printf("sendCmd: cmd=%d, id = %d, state=%d\r\n", cmd, id, state);
00354     if (0 == id) {
00355         id = getNextMsgId();
00356     }
00357     //pc.printf("next Id:%d\r\n", id);
00358 #ifdef BLYNK_MICRODUINO
00359     if (!conn.connected()) {
00360         //pc.printf("not connected, so just return!\r\n");
00361         return;
00362     }
00363 #else
00364     if (!conn.connected() || (cmd != BLYNK_CMD_RESPONSE && cmd != BLYNK_CMD_PING && cmd != BLYNK_CMD_LOGIN && state != CONNECTED) ) {
00365     //if (!conn.connected() || (cmd != BLYNK_CMD_RESPONSE && cmd != BLYNK_CMD_PING && cmd != BLYNK_CMD_LOGIN) ) {
00366 #ifdef BLYNK_DEBUG
00367         BLYNK_LOG2(BLYNK_F("Cmd skipped:"), cmd);
00368 #endif
00369         //pc.printf("Cmd skipped:", cmd);
00370         return;
00371     }
00372     asdf
00373 #endif
00374     const int full_length = (sizeof(BlynkHeader)) +
00375                             (data  ? length  : 0) +
00376                             (data2 ? length2 : 0);
00377     //pc.printf("full_length = %d\r\n", full_length);
00378 #if defined(BLYNK_SEND_ATOMIC) || defined(ESP8266) || defined(SPARK) || defined(PARTICLE) || defined(ENERGIA)
00379     // Those have more RAM and like single write at a time...
00380 
00381     uint8_t buff[full_length];
00382 
00383     BlynkHeader* hdr = (BlynkHeader*)buff;
00384     hdr->type = cmd;
00385     hdr->msg_id = htons(id);
00386     hdr->length = htons(length+length2);
00387 
00388     size_t pos = sizeof(BlynkHeader);
00389     if (data && length) {
00390         memcpy(buff + pos, data, length);
00391         pos += length;
00392     }
00393     if (data2 && length2) {
00394         memcpy(buff + pos, data2, length2);
00395     }
00396 
00397     size_t wlen = 0;
00398     while (wlen < full_length) {
00399         const size_t chunk = BlynkMin(size_t(BLYNK_SEND_CHUNK), full_length - wlen);
00400         BLYNK_DBG_DUMP("<", buff + wlen, chunk);
00401         const size_t w = conn.write(buff + wlen, chunk);
00402         wait_ms(BLYNK_SEND_THROTTLE);
00403         if (w == 0) {
00404 #ifdef BLYNK_DEBUG
00405             BLYNK_LOG1(BLYNK_F("Cmd error"));
00406 #endif
00407             conn.disconnect();
00408             state = CONNECTING;
00409             //BlynkOnDisconnected();
00410             return;
00411         }
00412         wlen += w;
00413     }
00414 
00415 #else
00416     BlynkHeader hdr;
00417     hdr.type = cmd;
00418     hdr.msg_id = htons(id);
00419     hdr.length = htons(length+length2);
00420 
00421     BLYNK_DBG_DUMP("<", &hdr, sizeof(hdr));
00422     size_t wlen = conn.write(&hdr, sizeof(hdr));
00423     wait_ms(BLYNK_SEND_THROTTLE);
00424 
00425     if (cmd != BLYNK_CMD_RESPONSE) {
00426         if (length) {
00427             BLYNK_DBG_DUMP("<", data, length);
00428             wlen += conn.write(data, length);
00429             wait_ms(BLYNK_SEND_THROTTLE);
00430         }
00431         if (length2) {
00432             BLYNK_DBG_DUMP("<", data2, length2);
00433             wlen += conn.write(data2, length2);
00434             wait_ms(BLYNK_SEND_THROTTLE);
00435         }
00436     }
00437 
00438 #endif
00439 
00440     if (wlen != full_length) {
00441 #ifdef BLYNK_DEBUG
00442         BLYNK_LOG4(BLYNK_F("Sent "), wlen, '/', full_length);
00443 #endif
00444         conn.disconnect();
00445         state = CONNECTING;
00446         //BlynkOnDisconnected();
00447         return;
00448     }
00449 
00450 #if defined BLYNK_MSG_LIMIT && BLYNK_MSG_LIMIT > 0
00451     const millis_time_t ts = this->getMillis();
00452     BlynkAverageSample<32>(deltaCmd, ts - lastActivityOut);
00453     lastActivityOut = ts;
00454     //BLYNK_LOG2(BLYNK_F("Delta: "), deltaCmd);
00455     if (deltaCmd < (1000/BLYNK_MSG_LIMIT)) {
00456         BLYNK_LOG_TROUBLE(BLYNK_F("flood-error"));
00457         conn.disconnect();
00458         state = CONNECTING;
00459         //BlynkOnDisconnected();
00460     }
00461 #else
00462     lastActivityOut = this->getMillis();
00463 #endif
00464 
00465 }
00466 
00467 template <class Transp>
00468 uint16_t BlynkProtocol<Transp>::getNextMsgId()
00469 {
00470     static uint16_t last = 0;
00471     if (currentMsgId != 0)
00472         return currentMsgId;
00473     if (++last == 0)
00474         last = 1;
00475     return last;
00476 }
00477 
00478 #endif
00479