ELClientPacket
25 | Pointer to ELClientPacket structure generated or NULL if it the message is from a callback or if an error occured
26 | @par Example
27 | @code
28 | no example code yet
29 | @endcode
30 | */
31 | ELClientPacket* ELClient::protoCompletedCb(void) {
32 | // the packet starts with a ELClientPacket
33 | ELClientPacket* packet = (ELClientPacket*)_proto.buf;
34 | if (_debugEn) {
35 | _debug->print("ELC: got ");
36 | _debug->print(_proto.dataLen);
37 | _debug->print(" @");
38 | _debug->print((uint32_t)_proto.buf, 16);
39 | _debug->print(": ");
40 | _debug->print(packet->cmd, 16);
41 | _debug->print(" ");
42 | _debug->print(packet->value, 16);
43 | _debug->print(" ");
44 | _debug->print(packet->argc, 16);
45 | for (uint16_t i=8; i<_proto.dataLen; i++) {
46 | _debug->print(" ");
47 | _debug->print(*(uint8_t*)(_proto.buf+i), 16);
48 | }
49 | _debug->println();
50 | }
51 |
52 | // verify CRC
53 | uint16_t crc = crc16Data(_proto.buf, _proto.dataLen-2, 0);
54 | uint16_t resp_crc = *(uint16_t*)(_proto.buf+_proto.dataLen-2);
55 | if (crc != resp_crc) {
56 | DBG("ELC: Invalid CRC");
57 | return NULL;
58 | }
59 |
60 | // dispatch based on command
61 | switch (packet->cmd) {
62 | case CMD_RESP_V: // response with a value: return the packet
63 | // value response
64 | if (_debugEn) {
65 | _debug->print("RESP_V: ");
66 | _debug->println(packet->value);
67 | }
68 | return packet;
69 | case CMD_RESP_CB: // response callback: perform the callback!
70 | FPELClientPacket
100 | Pointer to ELClientResponse structure with the received response
101 | @par Example
102 | @code
103 | void loop()
104 | {
105 | ELClientPacket *packet;
106 | // process any callbacks coming from esp_link
107 | packet = esp.Process();
108 | if (packet != 0)
109 | {
110 | // process the received package //
111 | }
112 | }
113 | @endcode
114 | */
115 | ELClientPacket *ELClient::Process() {
116 | int value;
117 | while (_serial->available()) {
118 | value = _serial->read();
119 | if (value == SLIP_ESC) {
120 | _proto.isEsc = 1;
121 | } else if (value == SLIP_END) {
122 | ELClientPacket *packet = _proto.dataLen >= 8 ? protoCompletedCb() : 0;
123 | _proto.dataLen = 0;
124 | _proto.isEsc = 0;
125 | if (packet != NULL) return packet;
126 | } else {
127 | if (_proto.isEsc) {
128 | if (value == SLIP_ESC_END) value = SLIP_END;
129 | if (value == SLIP_ESC_ESC) value = SLIP_ESC;
130 | _proto.isEsc = 0;
131 | }
132 | if (_proto.dataLen < _proto.bufSize) {
133 | _proto.buf[_proto.dataLen++] = value;
134 | }
135 | }
136 | }
137 | return NULL;
138 | }
139 |
140 | //===== Output
141 |
142 | /*! write(uint8_t data)
143 | @brief Send a byte
144 | @details Write a byte to the output stream and perform SLIP escaping
145 | @note
146 | This function is usually not needed for applications. The communication to the ESP8266 is handled by the cmd, rest, mqtt, tcp and udp library parts.
147 | @param data
148 | Byte to be sent
149 | @par Example
150 | @code
151 | no example code yet
152 | @endcode
153 | */
154 | void ELClient::write(uint8_t data) {
155 | switch (data) {
156 | case SLIP_END:
157 | _serial->write(SLIP_ESC);
158 | _serial->write(SLIP_ESC_END);
159 | break;
160 | case SLIP_ESC:
161 | _serial->write(SLIP_ESC);
162 | _serial->write(SLIP_ESC_ESC);
163 | break;
164 | default:
165 | _serial->write(data);
166 | }
167 | }
168 |
169 | /*! write(void* data, uint16_t len)
170 | @brief Send several byte
171 | @details Write some bytes to the output stream, no SLIP escaping is performed
172 | @note
173 | This function is usually not needed for applications. The communication to the ESP8266 is handled by the cmd, rest, mqtt, tcp and udp library parts.
174 | @param data
175 | Pointer to data buffer to be sent
176 | @param len
177 | Size of data buffer
178 | @par Example
179 | @code
180 | no example code yet
181 | @endcode
182 | */
183 | void ELClient::write(void* data, uint16_t len) {
184 | uint8_t *d = (uint8_t*)data;
185 | while (len--)
186 | write(*d++);
187 | }
188 |
189 | /*! Request(uint16_t cmd, uint32_t value, uint16_t argc)
190 | @brief Start a request
191 | @details Start preparing a request by sending the command, number of arguments
192 | and the first argument (which can be a callback pointer)
193 | @note
194 | This function is usually not needed for applications. The communication to the ESP8266 is handled by the cmd, rest, mqtt, tcp and udp library parts.
195 | @param cmd
196 | Command for the ESP, see enum CmdName for available commands
197 | @param value
198 | First argument or pointer to a callback function
199 | @param argc
200 | Number of arguments in this request
201 | @par Example
202 | @code
203 | _elc->Request(CMD_MQTT_LWT, 0, 4);
204 | _elc->Request(topic, strlen(topic));
205 | _elc->Request(message, strlen(message));
206 | _elc->Request(&qos, 1);
207 | _elc->Request(&retain, 1);
208 | _elc->Request();
209 | @endcode
210 | */
211 | void ELClient::Request(uint16_t cmd, uint32_t value, uint16_t argc) {
212 | crc = 0;
213 | _serial->write(SLIP_END);
214 | write(&cmd, 2);
215 | crc = crc16Data((unsigned const char*)&cmd, 2, crc);
216 |
217 | write(&argc, 2);
218 | crc = crc16Data((unsigned const char*)&argc, 2, crc);
219 |
220 | write(&value, 4);
221 | crc = crc16Data((unsigned const char*)&value, 4, crc);
222 | }
223 |
224 | /*! Request(uint16_t cmd, uint32_t value, uint16_t argc)
225 | @brief Append an argument to the request
226 | @details Send additional arguments as appendment to the ESP
227 | @note
228 | This function is usually not needed for applications. The communication to the ESP8266 is handled by the cmd, rest, mqtt, tcp and udp library parts.
229 | @param data
230 | Pointer to the buffer with the argument
231 | @param len
232 | Size of the argument buffer
233 | @par Example
234 | @code
235 | _elc->Request(CMD_MQTT_LWT, 0, 4);
236 | _elc->Request(topic, strlen(topic));
237 | _elc->Request(message, strlen(message));
238 | _elc->Request(&qos, 1);
239 | _elc->Request(&retain, 1);
240 | _elc->Request();
241 | @endcode
242 | */
243 | void ELClient::Request(const void* data, uint16_t len) {
244 | uint8_t *d = (uint8_t*)data;
245 |
246 | // write the length
247 | write(&len, 2);
248 | crc = crc16Data((unsigned const char*)&len, 2, crc);
249 |
250 | // output the data
251 | for (uint16_t l=len; l>0; l--) {
252 | write(*d);
253 | crc = crc16Add(*d, crc);
254 | d++;
255 | }
256 |
257 | // output padding
258 | uint16_t pad = (4-(len&3))&3;
259 | uint8_t temp = 0;
260 | while (pad--) {
261 | write(temp);
262 | crc = crc16Add(temp, crc);
263 | }
264 | }
265 |
266 | /*! Request(const __FlashStringHelper* data, uint16_t len)
267 | @brief Append an argument to the request
268 | @details Send additional arguments located in flash as appendment to the ESP
269 | @note
270 | This function is usually not needed for applications. The communication to the ESP8266 is handled by the cmd, rest, mqtt, tcp and udp library parts.
271 | @param data
272 | Pointer to the buffer with the argument
273 | @param len
274 | Size of the argument buffer
275 | @par Example
276 | @code
277 | _elc->Request(CMD_MQTT_LWT, 0, 4);
278 | _elc->Request(topic, strlen(topic));
279 | _elc->Request(message, strlen(message));
280 | _elc->Request(&qos, 1);
281 | _elc->Request(&retain, 1);
282 | _elc->Request();
283 | @endcode
284 | */
285 | void ELClient::Request(const __FlashStringHelper* data, uint16_t len) {
286 | // write the length
287 | write(&len, 2);
288 | crc = crc16Data((unsigned const char*)&len, 2, crc);
289 |
290 | // output the data
291 | PGM_P p = reinterpret_castELClientPacket
430 | Received packet or null if timeout occured
431 | @par Example
432 | @code
433 | // Wait for WiFi to be connected.
434 | esp.GetWifiStatus();
435 | ELClientPacket *packet;
436 | Serial.print("Waiting for WiFi ");
437 | if ((packet=esp.WaitReturn()) != NULL) {
438 | Serial.print(".");
439 | Serial.println(packet->value);
440 | }
441 | Serial.println("");
442 | @endcode
443 | */
444 | ELClientPacket *ELClient::WaitReturn(uint32_t timeout) {
445 | uint32_t wait = millis();
446 | while (millis() - wait < timeout) {
447 | ELClientPacket *packet = Process();
448 | if (packet != NULL) return packet;
449 | }
450 | return NULL;
451 | }
452 |
453 | //===== CRC helper functions
454 |
455 | /*! crc16Add(unsigned char b, uint16_t acc)
456 | @brief Create CRC for a byte add it to an existing CRC checksum and return the result
457 | @param b
458 | Byte which CRC will be added
459 | @param acc
460 | Existing CRC checksum
461 | @return uint16_t
462 | New CRC checksum
463 | @par Example
464 | @code
465 | no example code yet
466 | @endcode
467 | */
468 | uint16_t ELClient::crc16Add(unsigned char b, uint16_t acc)
469 | {
470 | acc ^= b;
471 | acc = (acc >> 8) | (acc << 8);
472 | acc ^= (acc & 0xff00) << 4;
473 | acc ^= (acc >> 8) >> 4;
474 | acc ^= (acc & 0xff00) >> 5;
475 | return acc;
476 | }
477 |
478 | /*! crc16Data(const unsigned char *data, uint16_t len, uint16_t acc)
479 | @brief Create/add CRC for a data buffer
480 | @param data
481 | The data buffer which will be CRCed
482 | @param len
483 | Size of the data buffer
484 | @param acc
485 | Existing CRC checksum
486 | @return uint16_t
487 | New CRC checksum
488 | @par Example
489 | @code
490 | no example code yet
491 | @endcode
492 | */
493 | uint16_t ELClient::crc16Data(const unsigned char *data, uint16_t len, uint16_t acc)
494 | {
495 | for (uint16_t i=0; iuint32_t
22 | current time as number of seconds
23 | - since Thu Jan 1 00:00:58 UTC 1970 if ESP has time from NTP
24 | - since last reboot of ESP if no NTP time is available
25 | @par Example
26 | @code
27 | uint32_t t = cmd.GetTime();
28 | Serial.print("Time: "); Serial.println(t);
29 | @endcode
30 | */
31 | uint32_t ELClientCmd::GetTime() {
32 | _elc->Request(CMD_GET_TIME, 0, 0);
33 | _elc->Request();
34 |
35 | ELClientPacket *pkt = _elc->WaitReturn();
36 | return pkt ? pkt->value : 0;
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/ELClient/ELClientCmd.h:
--------------------------------------------------------------------------------
1 | /*! \file ELClientCmd.h
2 | \brief Definitions for ELClientCmd
3 | \note Miscellaneous commands
4 | */
5 | // Miscellaneous commands
6 |
7 | #ifndef _EL_CLIENT_CMD_H_
8 | #define _EL_CLIENT_CMD_H_
9 |
10 | #include int16_t
41 | Size of argument
42 | @par Example
43 | @code
44 | no example code yet
45 | @endcode
46 | */
47 | int16_t ELClientResponse::popArgPtr(void **data) {
48 | if (_arg_num >= _cmd->argc) return -1;
49 |
50 | uint16_t len = *(uint16_t*)_arg_ptr;
51 | uint16_t pad = (4-((len+2)&3))&3; // pad to next multiple of 4, including length
52 | _arg_ptr += 2;
53 | _arg_num++;
54 |
55 | *data = _arg_ptr;
56 | _arg_ptr += len + pad;
57 | return len;
58 | }
59 |
60 | /*! popArg(void* d, uint16_t maxLen)
61 | @brief Extract an argument from the response packet
62 | @param d
63 | Pointer to buffer for the argument
64 | @param maxLen
65 | Size of the buffer for the argument
66 | @return int16_t
67 | Size of argument
68 | @par Example
69 | @code
70 | no example code yet
71 | @endcode
72 | */
73 | int16_t ELClientResponse::popArg(void* d, uint16_t maxLen) {
74 | if (_arg_num >= _cmd->argc) return -1;
75 |
76 | uint16_t len = *(uint16_t*)_arg_ptr;
77 | uint16_t pad = (4-((len+2)&3))&3; // pad to next multiple of 4, including length
78 | _arg_ptr += 2;
79 | _arg_num++;
80 |
81 | uint8_t *data = (uint8_t *)d;
82 | uint16_t l = len > maxLen ? maxLen : len;
83 | uint8_t *p = _arg_ptr;
84 | while (l--)
85 | *data++ = *p++;
86 |
87 | _arg_ptr += len + pad;
88 | return len;
89 | }
90 |
91 | /*! popChar(char* buffer)
92 | @brief Extract a character from the response packet
93 | @param buffer
94 | Pointer to buffer for the character
95 | @par Example
96 | @code
97 | no example code yet
98 | @endcode
99 | */
100 | void ELClientResponse::popChar(char* buffer) {
101 | uint16_t len = *(uint16_t*)_arg_ptr;
102 | uint16_t pad = (4-((len+2)&3))&3; // pad to next multiple of 4, including length
103 | _arg_ptr += 2;
104 | _arg_num++;
105 |
106 | uint8_t i;
107 | for (i = 0; i < len; i++) {
108 | buffer[i] = (char)*_arg_ptr++;
109 | }
110 | buffer[i] = '\0';
111 |
112 | _arg_ptr += pad;
113 | }
114 |
115 | /*! popString()
116 | @brief Extract a string from the response packet
117 | @return String
118 | String extracted from the response packet
119 | @par Example
120 | @code
121 | no example code yet
122 | @endcode
123 | */
124 | String ELClientResponse::popString() {
125 | String ret;
126 | uint16_t len = *(uint16_t*)_arg_ptr;
127 | uint16_t pad = (4-((len+2)&3))&3; // pad to next multiple of 4, including length
128 | _arg_ptr += 2;
129 | _arg_num++;
130 |
131 | while (len--)
132 | ret += (char)*_arg_ptr++;
133 |
134 | _arg_ptr += pad;
135 | return ret;
136 | }
137 |
138 | /*! popString(String* data)
139 | @brief Extract the pointer to a string from the response packet
140 | @param data
141 | Pointer to be set to the string in the response packet
142 | @par Example
143 | @code
144 | no example code yet
145 | @endcode
146 | */
147 | void ELClientResponse::popString(String* data) {
148 | uint16_t len = *(uint16_t*)_arg_ptr;
149 | uint16_t pad = (4-((len+2)&3))&3; // pad to next multiple of 4, including length
150 | _arg_ptr += 2;
151 | _arg_num++;
152 |
153 | while (len--)
154 | data->concat((char)*_arg_ptr++);
155 |
156 | _arg_ptr += pad;
157 | }
158 |
--------------------------------------------------------------------------------
/ELClient/ELClientResponse.h:
--------------------------------------------------------------------------------
1 | /*! \file ELClientResponse.h
2 | \brief Definitions for ELClientResponse
3 | */
4 | #ifndef _EL_CLIENT_RESPONSE_H_
5 | #define _EL_CLIENT_RESPONSE_H_
6 |
7 | #if _MSC_VER
8 | #define PACKED
9 | #else
10 | #define PACKED __attribute__ ((__packed__))
11 | #endif
12 |
13 | #include uint16_t
285 | Size of received packet or number of sent bytes or 0 if no response
286 | @par Example
287 | @code
288 | #define BUFLEN 266
289 | void loop()
290 | {
291 | // process any callbacks coming from esp_link
292 | esp.Process();
293 | void loop()
294 | {
295 | // process any callbacks coming from esp_link
296 | esp.Process();
297 | // if we're connected make an HTTP request
298 | if(wifiConnected)
299 | {
300 | // Request /utc/now from the previously set-up server
301 | rest.get("/utc/now");
302 | char response[BUFLEN];
303 | memset(response, 0, BUFLEN);
304 | uint16_t code = rest.waitResponse(response, BUFLEN);
305 | if(code == HTTP_STATUS_OK)
306 | {
307 | Serial.println("ARDUINO: GET successful:");
308 | Serial.println(response);
309 | }
310 | else
311 | {
312 | Serial.print("ARDUINO: GET failed: ");
313 | Serial.println(code);
314 | }
315 | delay(1000);
316 | }
317 | }
318 | }
319 | @endcode
320 | */
321 | uint16_t ELClientRest::getResponse(char* data, uint16_t maxLen)
322 | {
323 | if (_status == 0) return 0;
324 | memcpy(data, _data, _len>maxLen?maxLen:_len);
325 | int16_t s = _status;
326 | _status = 0;
327 | return s;
328 | }
329 |
330 | /*! waitResponse(char* data, uint16_t maxLen, uint32_t timeout)
331 | @brief Wait for the response
332 | @details Wait for the response from the remote server for time_out
,
333 | returns the HTTP status code, 0 if no response (may need to wait longer)
334 | @warning Blocks the Arduino code for 5 seconds! not recommended to use.
335 | Received packet is NOT null-terminated
336 | @param data
337 | Pointer to buffer for received packet
338 | @param maxLen
339 | Size of buffer for received packet. If the received packet is larger than the buffer, the received packet will be truncated.
340 | @param timeout
341 | (optional) Timout in milli seconds to wait for a response, defaults to 5000ms
342 | @return uint16_t
343 | Size of received packet or number of sent bytes or 0 if no response
344 | @par Example
345 | @code
346 | #define BUFLEN 266
347 | void loop()
348 | {
349 | // process any callbacks coming from esp_link
350 | esp.Process();
351 | // if we're connected make an HTTP request
352 | if(wifiConnected)
353 | {
354 | // Request /utc/now from the previously set-up server
355 | rest.get("/utc/now");
356 | char response[BUFLEN];
357 | memset(response, 0, BUFLEN);
358 | uint16_t code = rest.waitResponse(response, BUFLEN);
359 | if(code == HTTP_STATUS_OK)
360 | {
361 | Serial.println("ARDUINO: GET successful:");
362 | Serial.println(response);
363 | }
364 | else
365 | {
366 | Serial.print("ARDUINO: GET failed: ");
367 | Serial.println(code);
368 | }
369 | delay(1000);
370 | }
371 | }
372 | @endcode
373 | */
374 | uint16_t ELClientRest::waitResponse(char* data, uint16_t maxLen, uint32_t timeout)
375 | {
376 | uint32_t wait = millis();
377 | while (_status == 0 && (millis() - wait < timeout)) {
378 | _elc->Process();
379 | }
380 | return getResponse(data, maxLen);
381 | }
382 |
--------------------------------------------------------------------------------
/ELClient/ELClientRest.h:
--------------------------------------------------------------------------------
1 | /*! \file ELClientRest.h
2 | \brief Definitions for ELClientRes
3 | \author B. Runnels
4 | \author T. von Eicken
5 | \date 2016
6 | */
7 | // Copyright (c) 2016 by B. Runnels and T. von Eicken
8 |
9 | #ifndef _EL_CLIENT_REST_H_
10 | #define _EL_CLIENT_REST_H_
11 |
12 | #include uint16_t
203 | Size of received packet or number of sent bytes or 0 if no response
204 | @par Example
205 | @code
206 | #define BUFLEN 266
207 | void loop()
208 | {
209 | // process any callbacks coming from esp_link
210 | esp.Process();
211 | // Check if we received a packet or if the last send request has finished
212 | char response[BUFLEN];
213 | memset(response, 0, BUFLEN);
214 | uint8_t resp_type;
215 | uint8_t client_num;
216 | uint16_t len = socket.getResponse(&resp_type, &client_num, response, BUFLEN);
217 | if (len != 0)
218 | {
219 | if (resp_type == USERCB_SENT)
220 | {
221 | Serial.println("Sent "+String(len)+" bytes");
222 | }
223 | else
224 | {
225 | Serial.print("Received packet: ");
226 | for (int i=0; itimeout
seconds,
249 | returns the number of send or received bytes,
250 | 0 if no response (may need to wait longer)
251 | @warning Blocks the Arduino code for 5 seconds! not recommended to use. Use callback function instead!
252 | Received packet is NOT null-terminated
253 | @param resp_type
254 | Pointer to response type. Is USERCB_SENT if packet was sent or USERCB_RECV if a packet was received.
255 | @param client_num
256 | Pointer to connection number. Can be used to distinguish between different socket clients.
257 | @param data
258 | Pointer to buffer for received packet
259 | @param maxLen
260 | Size of buffer for received packet. If the received packet is larger than the buffer, the received packet will be truncated.
261 | @param timeout
262 | (optional) Timout in milli seconds to wait for a response, defaults to 5000ms
263 | @return uint16_t
264 | Size of received packet or number of sent bytes or 0 if no response
265 | @par Example
266 | @code
267 | #define BUFLEN 266
268 | bool haveRemoteResponse = true;
269 | void loop()
270 | {
271 | // process any callbacks coming from esp_link
272 | esp.Process();
273 | if (haveRemoteResponse) // If last packet was sent, send a new one
274 | {
275 | Serial.println("Sending JSON array to TCP server");
276 | char socketPacket = "{"device":"spm","s":622.02,"c":-165.86}"
277 | socket.send(socketPacket, 39);
278 | haveRemoteResponse = false;
279 | }
280 | // Check if we received a packet or if the last send request has finished
281 | char response[BUFLEN];
282 | memset(response, 0, BUFLEN);
283 | uint8_t resp_type;
284 | uint8_t client_num;
285 | uint16_t len = socket.waitResponse(&resp_type, &client_num, response, BUFLEN);
286 | if (len != 0)
287 | {
288 | if (resp_type == USERCB_SENT)
289 | {
290 | Serial.println("Sent "+String(len)+" bytes");
291 | }
292 | else
293 | {
294 | Serial.print("Received packet: ");
295 | for (int i=0; i