Blynk library for embedded hardware. Works with Arduino, ESP8266, Raspberry Pi, Intel Edison/Galileo, LinkIt ONE, Particle Core/Photon, Energia, ARM mbed, etc. http://www.blynk.cc/

Dependents:   Blynk_RBL_BLE_Nano Blynk_MicroBit Blynk_Serial Blynk_RBL_BLE_Nano

Committer:
vshymanskyy
Date:
Sat May 07 08:02:50 2016 +0000
Revision:
0:58b20b438383
Child:
3:31e4b850b126
First commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
vshymanskyy 0:58b20b438383 1 /**
vshymanskyy 0:58b20b438383 2 * @file BlynkProtocol.h
vshymanskyy 0:58b20b438383 3 * @author Volodymyr Shymanskyy
vshymanskyy 0:58b20b438383 4 * @license This project is released under the MIT License (MIT)
vshymanskyy 0:58b20b438383 5 * @copyright Copyright (c) 2015 Volodymyr Shymanskyy
vshymanskyy 0:58b20b438383 6 * @date Jan 2015
vshymanskyy 0:58b20b438383 7 * @brief Blynk protocol implementation
vshymanskyy 0:58b20b438383 8 *
vshymanskyy 0:58b20b438383 9 */
vshymanskyy 0:58b20b438383 10
vshymanskyy 0:58b20b438383 11 #ifndef BlynkProtocol_h
vshymanskyy 0:58b20b438383 12 #define BlynkProtocol_h
vshymanskyy 0:58b20b438383 13
vshymanskyy 0:58b20b438383 14 #include <string.h>
vshymanskyy 0:58b20b438383 15 #include <stdlib.h>
vshymanskyy 0:58b20b438383 16 #include <Blynk/BlynkDebug.h>
vshymanskyy 0:58b20b438383 17 #include <Blynk/BlynkProtocolDefs.h>
vshymanskyy 0:58b20b438383 18 #include <Blynk/BlynkApi.h>
vshymanskyy 0:58b20b438383 19 #include <utility/BlynkUtility.h>
vshymanskyy 0:58b20b438383 20
vshymanskyy 0:58b20b438383 21 template <class Transp>
vshymanskyy 0:58b20b438383 22 class BlynkProtocol
vshymanskyy 0:58b20b438383 23 : public BlynkApi< BlynkProtocol<Transp> >
vshymanskyy 0:58b20b438383 24 {
vshymanskyy 0:58b20b438383 25 friend class BlynkApi< BlynkProtocol<Transp> >;
vshymanskyy 0:58b20b438383 26 public:
vshymanskyy 0:58b20b438383 27 enum BlynkState {
vshymanskyy 0:58b20b438383 28 CONNECTING,
vshymanskyy 0:58b20b438383 29 CONNECTED,
vshymanskyy 0:58b20b438383 30 DISCONNECTED,
vshymanskyy 0:58b20b438383 31 };
vshymanskyy 0:58b20b438383 32
vshymanskyy 0:58b20b438383 33 BlynkProtocol(Transp& transp)
vshymanskyy 0:58b20b438383 34 : conn(transp)
vshymanskyy 0:58b20b438383 35 , authkey(NULL)
vshymanskyy 0:58b20b438383 36 , lastActivityIn(0)
vshymanskyy 0:58b20b438383 37 , lastActivityOut(0)
vshymanskyy 0:58b20b438383 38 , lastHeartbeat(0)
vshymanskyy 0:58b20b438383 39 #ifdef BLYNK_MSG_LIMIT
vshymanskyy 0:58b20b438383 40 , deltaCmd(0)
vshymanskyy 0:58b20b438383 41 #endif
vshymanskyy 0:58b20b438383 42 , currentMsgId(0)
vshymanskyy 0:58b20b438383 43 , state(CONNECTING)
vshymanskyy 0:58b20b438383 44 {}
vshymanskyy 0:58b20b438383 45
vshymanskyy 0:58b20b438383 46 bool connected() { return state == CONNECTED; }
vshymanskyy 0:58b20b438383 47
vshymanskyy 0:58b20b438383 48 bool connect(uint32_t timeout = BLYNK_TIMEOUT_MS*3) {
vshymanskyy 0:58b20b438383 49 conn.disconnect();
vshymanskyy 0:58b20b438383 50 state = CONNECTING;
vshymanskyy 0:58b20b438383 51 millis_time_t started = this->getMillis();
vshymanskyy 0:58b20b438383 52 while ((state != CONNECTED) &&
vshymanskyy 0:58b20b438383 53 (this->getMillis() - started < timeout))
vshymanskyy 0:58b20b438383 54 {
vshymanskyy 0:58b20b438383 55 run();
vshymanskyy 0:58b20b438383 56 }
vshymanskyy 0:58b20b438383 57 return state == CONNECTED;
vshymanskyy 0:58b20b438383 58 }
vshymanskyy 0:58b20b438383 59
vshymanskyy 0:58b20b438383 60 void disconnect() {
vshymanskyy 0:58b20b438383 61 conn.disconnect();
vshymanskyy 0:58b20b438383 62 state = DISCONNECTED;
vshymanskyy 0:58b20b438383 63 BLYNK_LOG1(BLYNK_F("Disconnected"));
vshymanskyy 0:58b20b438383 64 }
vshymanskyy 0:58b20b438383 65
vshymanskyy 0:58b20b438383 66 bool run(bool avail = false);
vshymanskyy 0:58b20b438383 67
vshymanskyy 0:58b20b438383 68 void startSession() {
vshymanskyy 0:58b20b438383 69 //TODO: conn.connect();
vshymanskyy 0:58b20b438383 70 state = CONNECTING;
vshymanskyy 0:58b20b438383 71 #ifdef BLYNK_MSG_LIMIT
vshymanskyy 0:58b20b438383 72 deltaCmd = 1000;
vshymanskyy 0:58b20b438383 73 #endif
vshymanskyy 0:58b20b438383 74 currentMsgId = 0;
vshymanskyy 0:58b20b438383 75 lastHeartbeat = lastActivityIn = lastActivityOut = this->getMillis(); // TODO: - 5005UL
vshymanskyy 0:58b20b438383 76 }
vshymanskyy 0:58b20b438383 77
vshymanskyy 0:58b20b438383 78 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);
vshymanskyy 0:58b20b438383 79
vshymanskyy 0:58b20b438383 80 private:
vshymanskyy 0:58b20b438383 81 int readHeader(BlynkHeader& hdr);
vshymanskyy 0:58b20b438383 82 uint16_t getNextMsgId();
vshymanskyy 0:58b20b438383 83
vshymanskyy 0:58b20b438383 84 protected:
vshymanskyy 0:58b20b438383 85 void begin(const char* auth) {
vshymanskyy 0:58b20b438383 86 BLYNK_LOG1(BLYNK_F("Blynk v" BLYNK_VERSION " on " BLYNK_INFO_DEVICE));
vshymanskyy 0:58b20b438383 87 this->authkey = auth;
vshymanskyy 0:58b20b438383 88 }
vshymanskyy 0:58b20b438383 89 bool processInput(void);
vshymanskyy 0:58b20b438383 90
vshymanskyy 0:58b20b438383 91 Transp& conn;
vshymanskyy 0:58b20b438383 92
vshymanskyy 0:58b20b438383 93 private:
vshymanskyy 0:58b20b438383 94 const char* authkey;
vshymanskyy 0:58b20b438383 95 millis_time_t lastActivityIn;
vshymanskyy 0:58b20b438383 96 millis_time_t lastActivityOut;
vshymanskyy 0:58b20b438383 97 union {
vshymanskyy 0:58b20b438383 98 millis_time_t lastHeartbeat;
vshymanskyy 0:58b20b438383 99 millis_time_t lastLogin;
vshymanskyy 0:58b20b438383 100 };
vshymanskyy 0:58b20b438383 101 #ifdef BLYNK_MSG_LIMIT
vshymanskyy 0:58b20b438383 102 millis_time_t deltaCmd;
vshymanskyy 0:58b20b438383 103 #endif
vshymanskyy 0:58b20b438383 104 uint16_t currentMsgId;
vshymanskyy 0:58b20b438383 105 BlynkState state;
vshymanskyy 0:58b20b438383 106 };
vshymanskyy 0:58b20b438383 107
vshymanskyy 0:58b20b438383 108 template <class Transp>
vshymanskyy 0:58b20b438383 109 bool BlynkProtocol<Transp>::run(bool avail)
vshymanskyy 0:58b20b438383 110 {
vshymanskyy 0:58b20b438383 111 #if !defined(BLYNK_NO_YIELD)
vshymanskyy 0:58b20b438383 112 yield();
vshymanskyy 0:58b20b438383 113 #endif
vshymanskyy 0:58b20b438383 114
vshymanskyy 0:58b20b438383 115 if (state == DISCONNECTED) {
vshymanskyy 0:58b20b438383 116 return false;
vshymanskyy 0:58b20b438383 117 }
vshymanskyy 0:58b20b438383 118
vshymanskyy 0:58b20b438383 119 const bool tconn = conn.connected();
vshymanskyy 0:58b20b438383 120
vshymanskyy 0:58b20b438383 121 if (tconn) {
vshymanskyy 0:58b20b438383 122 if (avail || conn.available() > 0) {
vshymanskyy 0:58b20b438383 123 //BLYNK_LOG2(BLYNK_F("Available: "), conn.available());
vshymanskyy 0:58b20b438383 124 //const unsigned long t = micros();
vshymanskyy 0:58b20b438383 125 if (!processInput()) {
vshymanskyy 0:58b20b438383 126 conn.disconnect();
vshymanskyy 0:58b20b438383 127 // TODO: Only when in direct mode?
vshymanskyy 0:58b20b438383 128 #ifdef BLYNK_USE_DIRECT_CONNECT
vshymanskyy 0:58b20b438383 129 state = CONNECTING;
vshymanskyy 0:58b20b438383 130 #endif
vshymanskyy 0:58b20b438383 131 //BlynkOnDisconnected();
vshymanskyy 0:58b20b438383 132 return false;
vshymanskyy 0:58b20b438383 133 }
vshymanskyy 0:58b20b438383 134 //BLYNK_LOG2(BLYNK_F("Proc time: "), micros() - t);
vshymanskyy 0:58b20b438383 135 }
vshymanskyy 0:58b20b438383 136 }
vshymanskyy 0:58b20b438383 137
vshymanskyy 0:58b20b438383 138 const millis_time_t t = this->getMillis();
vshymanskyy 0:58b20b438383 139
vshymanskyy 0:58b20b438383 140 if (state == CONNECTED) {
vshymanskyy 0:58b20b438383 141 if (!tconn) {
vshymanskyy 0:58b20b438383 142 state = CONNECTING;
vshymanskyy 0:58b20b438383 143 lastHeartbeat = t;
vshymanskyy 0:58b20b438383 144 //BlynkOnDisconnected();
vshymanskyy 0:58b20b438383 145 return false;
vshymanskyy 0:58b20b438383 146 }
vshymanskyy 0:58b20b438383 147
vshymanskyy 0:58b20b438383 148 if (t - lastActivityIn > (1000UL * BLYNK_HEARTBEAT + BLYNK_TIMEOUT_MS*3)) {
vshymanskyy 0:58b20b438383 149 #ifdef BLYNK_DEBUG
vshymanskyy 0:58b20b438383 150 BLYNK_LOG6(BLYNK_F("Heartbeat timeout: "), t, BLYNK_F(", "), lastActivityIn, BLYNK_F(", "), lastHeartbeat);
vshymanskyy 0:58b20b438383 151 #else
vshymanskyy 0:58b20b438383 152 BLYNK_LOG1(BLYNK_F("Heartbeat timeout"));
vshymanskyy 0:58b20b438383 153 #endif
vshymanskyy 0:58b20b438383 154 conn.disconnect();
vshymanskyy 0:58b20b438383 155 state = CONNECTING;
vshymanskyy 0:58b20b438383 156 //BlynkOnDisconnected();
vshymanskyy 0:58b20b438383 157 return false;
vshymanskyy 0:58b20b438383 158 } else if ((t - lastActivityIn > 1000UL * BLYNK_HEARTBEAT ||
vshymanskyy 0:58b20b438383 159 t - lastActivityOut > 1000UL * BLYNK_HEARTBEAT) &&
vshymanskyy 0:58b20b438383 160 t - lastHeartbeat > BLYNK_TIMEOUT_MS)
vshymanskyy 0:58b20b438383 161 {
vshymanskyy 0:58b20b438383 162 // Send ping if we didn't either send or receive something
vshymanskyy 0:58b20b438383 163 // for BLYNK_HEARTBEAT seconds
vshymanskyy 0:58b20b438383 164 sendCmd(BLYNK_CMD_PING);
vshymanskyy 0:58b20b438383 165 lastHeartbeat = t;
vshymanskyy 0:58b20b438383 166 }
vshymanskyy 0:58b20b438383 167 #ifndef BLYNK_USE_DIRECT_CONNECT
vshymanskyy 0:58b20b438383 168 } else if (state == CONNECTING) {
vshymanskyy 0:58b20b438383 169 if (tconn && (t - lastLogin > BLYNK_TIMEOUT_MS)) {
vshymanskyy 0:58b20b438383 170 BLYNK_LOG1(BLYNK_F("Login timeout"));
vshymanskyy 0:58b20b438383 171 conn.disconnect();
vshymanskyy 0:58b20b438383 172 state = CONNECTING;
vshymanskyy 0:58b20b438383 173 return false;
vshymanskyy 0:58b20b438383 174 } else if (!tconn && (t - lastLogin > 5000UL)) {
vshymanskyy 0:58b20b438383 175 conn.disconnect();
vshymanskyy 0:58b20b438383 176 if (!conn.connect()) {
vshymanskyy 0:58b20b438383 177 lastLogin = t;
vshymanskyy 0:58b20b438383 178 return false;
vshymanskyy 0:58b20b438383 179 }
vshymanskyy 0:58b20b438383 180
vshymanskyy 0:58b20b438383 181 #ifdef BLYNK_MSG_LIMIT
vshymanskyy 0:58b20b438383 182 deltaCmd = 1000;
vshymanskyy 0:58b20b438383 183 #endif
vshymanskyy 0:58b20b438383 184 sendCmd(BLYNK_CMD_LOGIN, 1, authkey, strlen(authkey));
vshymanskyy 0:58b20b438383 185 lastLogin = lastActivityOut;
vshymanskyy 0:58b20b438383 186 return true;
vshymanskyy 0:58b20b438383 187 }
vshymanskyy 0:58b20b438383 188 #endif
vshymanskyy 0:58b20b438383 189 }
vshymanskyy 0:58b20b438383 190 return true;
vshymanskyy 0:58b20b438383 191 }
vshymanskyy 0:58b20b438383 192
vshymanskyy 0:58b20b438383 193 template <class Transp>
vshymanskyy 0:58b20b438383 194 BLYNK_FORCE_INLINE
vshymanskyy 0:58b20b438383 195 bool BlynkProtocol<Transp>::processInput(void)
vshymanskyy 0:58b20b438383 196 {
vshymanskyy 0:58b20b438383 197 BlynkHeader hdr;
vshymanskyy 0:58b20b438383 198 const int ret = readHeader(hdr);
vshymanskyy 0:58b20b438383 199
vshymanskyy 0:58b20b438383 200 if (ret == 0) {
vshymanskyy 0:58b20b438383 201 return true; // Considered OK (no data on input)
vshymanskyy 0:58b20b438383 202 }
vshymanskyy 0:58b20b438383 203
vshymanskyy 0:58b20b438383 204 if (ret < 0 || hdr.msg_id == 0) {
vshymanskyy 0:58b20b438383 205 #ifdef BLYNK_DEBUG
vshymanskyy 0:58b20b438383 206 BLYNK_LOG1(BLYNK_F("Wrong header on input"));
vshymanskyy 0:58b20b438383 207 #endif
vshymanskyy 0:58b20b438383 208 return false;
vshymanskyy 0:58b20b438383 209 }
vshymanskyy 0:58b20b438383 210
vshymanskyy 0:58b20b438383 211 if (hdr.type == BLYNK_CMD_RESPONSE) {
vshymanskyy 0:58b20b438383 212 lastActivityIn = this->getMillis();
vshymanskyy 0:58b20b438383 213
vshymanskyy 0:58b20b438383 214 #ifndef BLYNK_USE_DIRECT_CONNECT
vshymanskyy 0:58b20b438383 215 if (state == CONNECTING && (1 == hdr.msg_id)) {
vshymanskyy 0:58b20b438383 216 switch (hdr.length) {
vshymanskyy 0:58b20b438383 217 case BLYNK_SUCCESS:
vshymanskyy 0:58b20b438383 218 case BLYNK_ALREADY_LOGGED_IN:
vshymanskyy 0:58b20b438383 219 BLYNK_LOG3(BLYNK_F("Ready (ping: "), lastActivityIn-lastHeartbeat, BLYNK_F("ms)."));
vshymanskyy 0:58b20b438383 220 lastHeartbeat = lastActivityIn;
vshymanskyy 0:58b20b438383 221 state = CONNECTED;
vshymanskyy 0:58b20b438383 222 this->sendInfo();
vshymanskyy 0:58b20b438383 223 #if !defined(BLYNK_NO_YIELD)
vshymanskyy 0:58b20b438383 224 yield();
vshymanskyy 0:58b20b438383 225 #endif
vshymanskyy 0:58b20b438383 226 BlynkOnConnected();
vshymanskyy 0:58b20b438383 227 return true;
vshymanskyy 0:58b20b438383 228 case BLYNK_INVALID_TOKEN:
vshymanskyy 0:58b20b438383 229 BLYNK_LOG1(BLYNK_F("Invalid auth token"));
vshymanskyy 0:58b20b438383 230 break;
vshymanskyy 0:58b20b438383 231 default:
vshymanskyy 0:58b20b438383 232 BLYNK_LOG2(BLYNK_F("Connect failed. code: "), hdr.length);
vshymanskyy 0:58b20b438383 233 }
vshymanskyy 0:58b20b438383 234 return false;
vshymanskyy 0:58b20b438383 235 }
vshymanskyy 0:58b20b438383 236 if (BLYNK_NOT_AUTHENTICATED == hdr.length) {
vshymanskyy 0:58b20b438383 237 return false;
vshymanskyy 0:58b20b438383 238 }
vshymanskyy 0:58b20b438383 239 #endif
vshymanskyy 0:58b20b438383 240 // TODO: return code may indicate App presence
vshymanskyy 0:58b20b438383 241 return true;
vshymanskyy 0:58b20b438383 242 }
vshymanskyy 0:58b20b438383 243
vshymanskyy 0:58b20b438383 244 if (hdr.length > BLYNK_MAX_READBYTES) {
vshymanskyy 0:58b20b438383 245 #ifdef BLYNK_DEBUG
vshymanskyy 0:58b20b438383 246 BLYNK_LOG2(BLYNK_F("Packet too big: "), hdr.length);
vshymanskyy 0:58b20b438383 247 #endif
vshymanskyy 0:58b20b438383 248 return false;
vshymanskyy 0:58b20b438383 249 }
vshymanskyy 0:58b20b438383 250
vshymanskyy 0:58b20b438383 251 uint8_t inputBuffer[hdr.length+1]; // Add 1 to zero-terminate
vshymanskyy 0:58b20b438383 252 if (hdr.length != conn.read(inputBuffer, hdr.length)) {
vshymanskyy 0:58b20b438383 253 #ifdef DEBUG
vshymanskyy 0:58b20b438383 254 BLYNK_LOG1(BLYNK_F("Can't read body"));
vshymanskyy 0:58b20b438383 255 #endif
vshymanskyy 0:58b20b438383 256 return false;
vshymanskyy 0:58b20b438383 257 }
vshymanskyy 0:58b20b438383 258 inputBuffer[hdr.length] = '\0';
vshymanskyy 0:58b20b438383 259
vshymanskyy 0:58b20b438383 260 BLYNK_DBG_DUMP(">", inputBuffer, hdr.length);
vshymanskyy 0:58b20b438383 261
vshymanskyy 0:58b20b438383 262 lastActivityIn = this->getMillis();
vshymanskyy 0:58b20b438383 263
vshymanskyy 0:58b20b438383 264 switch (hdr.type)
vshymanskyy 0:58b20b438383 265 {
vshymanskyy 0:58b20b438383 266 #ifdef BLYNK_USE_DIRECT_CONNECT
vshymanskyy 0:58b20b438383 267 case BLYNK_CMD_LOGIN: {
vshymanskyy 0:58b20b438383 268 if (!strncmp(authkey, (char*)inputBuffer, 32)) {
vshymanskyy 0:58b20b438383 269 state = CONNECTED;
vshymanskyy 0:58b20b438383 270 sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_SUCCESS);
vshymanskyy 0:58b20b438383 271 this->sendInfo();
vshymanskyy 0:58b20b438383 272 } else {
vshymanskyy 0:58b20b438383 273 sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_INVALID_TOKEN);
vshymanskyy 0:58b20b438383 274 }
vshymanskyy 0:58b20b438383 275 } break;
vshymanskyy 0:58b20b438383 276 #endif
vshymanskyy 0:58b20b438383 277 case BLYNK_CMD_PING: {
vshymanskyy 0:58b20b438383 278 sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_SUCCESS);
vshymanskyy 0:58b20b438383 279 } break;
vshymanskyy 0:58b20b438383 280 case BLYNK_CMD_HARDWARE:
vshymanskyy 0:58b20b438383 281 case BLYNK_CMD_BRIDGE: {
vshymanskyy 0:58b20b438383 282 currentMsgId = hdr.msg_id;
vshymanskyy 0:58b20b438383 283 this->processCmd(inputBuffer, hdr.length);
vshymanskyy 0:58b20b438383 284 currentMsgId = 0;
vshymanskyy 0:58b20b438383 285 } break;
vshymanskyy 0:58b20b438383 286 default: {
vshymanskyy 0:58b20b438383 287 #ifdef BLYNK_DEBUG
vshymanskyy 0:58b20b438383 288 BLYNK_LOG2(BLYNK_F("Invalid header type: "), hdr.type);
vshymanskyy 0:58b20b438383 289 #endif
vshymanskyy 0:58b20b438383 290 } break;
vshymanskyy 0:58b20b438383 291 }
vshymanskyy 0:58b20b438383 292
vshymanskyy 0:58b20b438383 293 return true;
vshymanskyy 0:58b20b438383 294 }
vshymanskyy 0:58b20b438383 295
vshymanskyy 0:58b20b438383 296 template <class Transp>
vshymanskyy 0:58b20b438383 297 int BlynkProtocol<Transp>::readHeader(BlynkHeader& hdr)
vshymanskyy 0:58b20b438383 298 {
vshymanskyy 0:58b20b438383 299 size_t rlen = conn.read(&hdr, sizeof(hdr));
vshymanskyy 0:58b20b438383 300 if (rlen == 0) {
vshymanskyy 0:58b20b438383 301 return 0;
vshymanskyy 0:58b20b438383 302 }
vshymanskyy 0:58b20b438383 303
vshymanskyy 0:58b20b438383 304 if (sizeof(hdr) != rlen) {
vshymanskyy 0:58b20b438383 305 return -1;
vshymanskyy 0:58b20b438383 306 }
vshymanskyy 0:58b20b438383 307 hdr.msg_id = ntohs(hdr.msg_id);
vshymanskyy 0:58b20b438383 308 hdr.length = ntohs(hdr.length);
vshymanskyy 0:58b20b438383 309
vshymanskyy 0:58b20b438383 310 BLYNK_DBG_DUMP(">", &hdr, sizeof(BlynkHeader));
vshymanskyy 0:58b20b438383 311 return rlen;
vshymanskyy 0:58b20b438383 312 }
vshymanskyy 0:58b20b438383 313
vshymanskyy 0:58b20b438383 314 #ifndef BLYNK_SEND_THROTTLE
vshymanskyy 0:58b20b438383 315 #define BLYNK_SEND_THROTTLE 0
vshymanskyy 0:58b20b438383 316 #endif
vshymanskyy 0:58b20b438383 317
vshymanskyy 0:58b20b438383 318 #ifndef BLYNK_SEND_CHUNK
vshymanskyy 0:58b20b438383 319 #define BLYNK_SEND_CHUNK 1024 // Just a big number
vshymanskyy 0:58b20b438383 320 #endif
vshymanskyy 0:58b20b438383 321
vshymanskyy 0:58b20b438383 322 template <class Transp>
vshymanskyy 0:58b20b438383 323 void BlynkProtocol<Transp>::sendCmd(uint8_t cmd, uint16_t id, const void* data, size_t length, const void* data2, size_t length2)
vshymanskyy 0:58b20b438383 324 {
vshymanskyy 0:58b20b438383 325 if (0 == id) {
vshymanskyy 0:58b20b438383 326 id = getNextMsgId();
vshymanskyy 0:58b20b438383 327 }
vshymanskyy 0:58b20b438383 328
vshymanskyy 0:58b20b438383 329 if (!conn.connected() || (cmd != BLYNK_CMD_RESPONSE && cmd != BLYNK_CMD_PING && cmd != BLYNK_CMD_LOGIN && state != CONNECTED) ) {
vshymanskyy 0:58b20b438383 330 #ifdef BLYNK_DEBUG
vshymanskyy 0:58b20b438383 331 BLYNK_LOG2(BLYNK_F("Cmd skipped:"), cmd);
vshymanskyy 0:58b20b438383 332 #endif
vshymanskyy 0:58b20b438383 333 return;
vshymanskyy 0:58b20b438383 334 }
vshymanskyy 0:58b20b438383 335
vshymanskyy 0:58b20b438383 336 const int full_length = (sizeof(BlynkHeader)) +
vshymanskyy 0:58b20b438383 337 (data ? length : 0) +
vshymanskyy 0:58b20b438383 338 (data2 ? length2 : 0);
vshymanskyy 0:58b20b438383 339
vshymanskyy 0:58b20b438383 340 #if defined(BLYNK_SEND_ATOMIC) || defined(ESP8266) || defined(SPARK) || defined(PARTICLE) || defined(ENERGIA)
vshymanskyy 0:58b20b438383 341 // Those have more RAM and like single write at a time...
vshymanskyy 0:58b20b438383 342
vshymanskyy 0:58b20b438383 343 uint8_t buff[full_length];
vshymanskyy 0:58b20b438383 344
vshymanskyy 0:58b20b438383 345 BlynkHeader* hdr = (BlynkHeader*)buff;
vshymanskyy 0:58b20b438383 346 hdr->type = cmd;
vshymanskyy 0:58b20b438383 347 hdr->msg_id = htons(id);
vshymanskyy 0:58b20b438383 348 hdr->length = htons(length+length2);
vshymanskyy 0:58b20b438383 349
vshymanskyy 0:58b20b438383 350 size_t pos = sizeof(BlynkHeader);
vshymanskyy 0:58b20b438383 351 if (data && length) {
vshymanskyy 0:58b20b438383 352 memcpy(buff + pos, data, length);
vshymanskyy 0:58b20b438383 353 pos += length;
vshymanskyy 0:58b20b438383 354 }
vshymanskyy 0:58b20b438383 355 if (data2 && length2) {
vshymanskyy 0:58b20b438383 356 memcpy(buff + pos, data2, length2);
vshymanskyy 0:58b20b438383 357 }
vshymanskyy 0:58b20b438383 358
vshymanskyy 0:58b20b438383 359 size_t wlen = 0;
vshymanskyy 0:58b20b438383 360 while (wlen < full_length) {
vshymanskyy 0:58b20b438383 361 const size_t chunk = BlynkMin(size_t(BLYNK_SEND_CHUNK), full_length - wlen);
vshymanskyy 0:58b20b438383 362 BLYNK_DBG_DUMP("<", buff + wlen, chunk);
vshymanskyy 0:58b20b438383 363 const size_t w = conn.write(buff + wlen, chunk);
vshymanskyy 0:58b20b438383 364 delay(BLYNK_SEND_THROTTLE);
vshymanskyy 0:58b20b438383 365 if (w == 0) {
vshymanskyy 0:58b20b438383 366 #ifdef BLYNK_DEBUG
vshymanskyy 0:58b20b438383 367 BLYNK_LOG1(BLYNK_F("Cmd error"));
vshymanskyy 0:58b20b438383 368 #endif
vshymanskyy 0:58b20b438383 369 conn.disconnect();
vshymanskyy 0:58b20b438383 370 state = CONNECTING;
vshymanskyy 0:58b20b438383 371 //BlynkOnDisconnected();
vshymanskyy 0:58b20b438383 372 return;
vshymanskyy 0:58b20b438383 373 }
vshymanskyy 0:58b20b438383 374 wlen += w;
vshymanskyy 0:58b20b438383 375 }
vshymanskyy 0:58b20b438383 376
vshymanskyy 0:58b20b438383 377 #else
vshymanskyy 0:58b20b438383 378
vshymanskyy 0:58b20b438383 379 BlynkHeader hdr;
vshymanskyy 0:58b20b438383 380 hdr.type = cmd;
vshymanskyy 0:58b20b438383 381 hdr.msg_id = htons(id);
vshymanskyy 0:58b20b438383 382 hdr.length = htons(length+length2);
vshymanskyy 0:58b20b438383 383
vshymanskyy 0:58b20b438383 384 BLYNK_DBG_DUMP("<", &hdr, sizeof(hdr));
vshymanskyy 0:58b20b438383 385 size_t wlen = conn.write(&hdr, sizeof(hdr));
vshymanskyy 0:58b20b438383 386 delay(BLYNK_SEND_THROTTLE);
vshymanskyy 0:58b20b438383 387
vshymanskyy 0:58b20b438383 388 if (cmd != BLYNK_CMD_RESPONSE) {
vshymanskyy 0:58b20b438383 389 if (length) {
vshymanskyy 0:58b20b438383 390 BLYNK_DBG_DUMP("<", data, length);
vshymanskyy 0:58b20b438383 391 wlen += conn.write(data, length);
vshymanskyy 0:58b20b438383 392 delay(BLYNK_SEND_THROTTLE);
vshymanskyy 0:58b20b438383 393 }
vshymanskyy 0:58b20b438383 394 if (length2) {
vshymanskyy 0:58b20b438383 395 BLYNK_DBG_DUMP("<", data2, length2);
vshymanskyy 0:58b20b438383 396 wlen += conn.write(data2, length2);
vshymanskyy 0:58b20b438383 397 delay(BLYNK_SEND_THROTTLE);
vshymanskyy 0:58b20b438383 398 }
vshymanskyy 0:58b20b438383 399 }
vshymanskyy 0:58b20b438383 400
vshymanskyy 0:58b20b438383 401 #endif
vshymanskyy 0:58b20b438383 402
vshymanskyy 0:58b20b438383 403 if (wlen != full_length) {
vshymanskyy 0:58b20b438383 404 #ifdef BLYNK_DEBUG
vshymanskyy 0:58b20b438383 405 BLYNK_LOG4(BLYNK_F("Sent "), wlen, '/', full_length);
vshymanskyy 0:58b20b438383 406 #endif
vshymanskyy 0:58b20b438383 407 conn.disconnect();
vshymanskyy 0:58b20b438383 408 state = CONNECTING;
vshymanskyy 0:58b20b438383 409 //BlynkOnDisconnected();
vshymanskyy 0:58b20b438383 410 return;
vshymanskyy 0:58b20b438383 411 }
vshymanskyy 0:58b20b438383 412
vshymanskyy 0:58b20b438383 413 #if defined BLYNK_MSG_LIMIT && BLYNK_MSG_LIMIT > 0
vshymanskyy 0:58b20b438383 414 const millis_time_t ts = this->getMillis();
vshymanskyy 0:58b20b438383 415 BlynkAverageSample<32>(deltaCmd, ts - lastActivityOut);
vshymanskyy 0:58b20b438383 416 lastActivityOut = ts;
vshymanskyy 0:58b20b438383 417 //BLYNK_LOG2(BLYNK_F("Delta: "), deltaCmd);
vshymanskyy 0:58b20b438383 418 if (deltaCmd < (1000/BLYNK_MSG_LIMIT)) {
vshymanskyy 0:58b20b438383 419 BLYNK_LOG_TROUBLE(BLYNK_F("flood-error"));
vshymanskyy 0:58b20b438383 420 conn.disconnect();
vshymanskyy 0:58b20b438383 421 state = CONNECTING;
vshymanskyy 0:58b20b438383 422 //BlynkOnDisconnected();
vshymanskyy 0:58b20b438383 423 }
vshymanskyy 0:58b20b438383 424 #else
vshymanskyy 0:58b20b438383 425 lastActivityOut = this->getMillis();
vshymanskyy 0:58b20b438383 426 #endif
vshymanskyy 0:58b20b438383 427
vshymanskyy 0:58b20b438383 428 }
vshymanskyy 0:58b20b438383 429
vshymanskyy 0:58b20b438383 430 template <class Transp>
vshymanskyy 0:58b20b438383 431 uint16_t BlynkProtocol<Transp>::getNextMsgId()
vshymanskyy 0:58b20b438383 432 {
vshymanskyy 0:58b20b438383 433 static uint16_t last = 0;
vshymanskyy 0:58b20b438383 434 if (currentMsgId != 0)
vshymanskyy 0:58b20b438383 435 return currentMsgId;
vshymanskyy 0:58b20b438383 436 if (++last == 0)
vshymanskyy 0:58b20b438383 437 last = 1;
vshymanskyy 0:58b20b438383 438 return last;
vshymanskyy 0:58b20b438383 439 }
vshymanskyy 0:58b20b438383 440
vshymanskyy 0:58b20b438383 441 #endif