Gbox 4.20
Grow box automation and monitoring - <a href='https://sites.google.com/site/growboxguy/'>https://sites.google.com/site/growboxguy/</a>
 
Loading...
Searching...
No Matches
ELClient.cpp
Go to the documentation of this file.
1
7// Copyright (c) 2016 by B. Runnels and T. von Eicken
8
9#include "ELClient.h"
10
11#define SLIP_END 0300
12#define SLIP_ESC 0333
13#define SLIP_ESC_END 0334
14#define SLIP_ESC_ESC 0335
16//===== Input
17
32 // the packet starts with a ELClientPacket
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!
71 // callback reponse
72 if (_debugEn) {
73 _debug->print("RESP_CB: ");
74 _debug->print(packet->value);
75 _debug->print(" ");
76 _debug->println(packet->argc);
77 }
78 fp = (FP<void, void*>*)packet->value;
79 if (fp->attached()) {
80 ELClientResponse resp(packet);
81 (*fp)(&resp);
82 }
83 return NULL;
84 case CMD_SYNC: // esp-link is not in sync, it may have reset, signal up the stack
85 _debug->println("NEED_SYNC!");
86 if (resetCb != NULL) (*resetCb)();
87 return NULL;
88 default:
89 // command (NOT IMPLEMENTED)
90 if (_debugEn) _debug->println("CMD??");
91 return NULL;
92 }
93}
94
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 }
133 _proto.buf[_proto.dataLen++] = value;
134 }
135 }
136 }
137 return NULL;
138}
139
140//===== Output
141
154void 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
183void ELClient::write(void* data, uint16_t len) {
184 uint8_t *d = (uint8_t*)data;
185 while (len--)
186 write(*d++);
187}
188
211void 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
243void 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
285void 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_cast<PGM_P>(data);
292 for (uint16_t l=len; l>0; l--) {
293 uint8_t c = pgm_read_byte(p++);
294 write(c);
295 crc = crc16Add(c, crc);
296 }
297
298 // output padding
299 uint16_t pad = (4-(len&3))&3;
300 uint8_t temp = 0;
301 while (pad--) {
302 write(temp);
303 crc = crc16Add(temp, crc);
304 }
305}
306
323 write((uint8_t*)&crc, 2);
324 _serial->write(SLIP_END);
325}
326
327//===== Initialization
328
341 _proto.bufSize = sizeof(_protoBuf);
342 _proto.dataLen = 0;
343 _proto.isEsc = 0;
344}
345
371ELClient::ELClient(Stream* serial) :
372_serial(serial) {
373 _debugEn = false;
374 init();
375}
376
404ELClient::ELClient(Stream* serial, Stream* debug) :
405_debug(debug), _serial(serial) {
406 _debugEn = true;
407 init();
408}
409
419void ELClient::DBG(const char* info) {
420 if (_debugEn) _debug->println(info);
421}
422
423//===== Responses
424
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
468uint16_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
493uint16_t ELClient::crc16Data(const unsigned char *data, uint16_t len, uint16_t acc)
494{
495 for (uint16_t i=0; i<len; i++)
496 acc = crc16Add(*data++, acc);
497 return acc;
498}
499
500//===== Basic requests built into ElClient
501
521boolean ELClient::Sync(uint32_t timeout) {
522 // send a SLIP END char to make sure we get a clean start
523 _serial->write(SLIP_END);
524 // send sync request
525 Request(CMD_SYNC, (uint32_t)&wifiCb, 0);
526 Request();
527 // we don't want to get a stale response that we need to sync 'cause that has the effect of
528 // calling us again recursively....
529 void (*rr)() = resetCb;
530 resetCb = NULL;
531 // empty the response queue hoping to find the wifiCb address
532 ELClientPacket *packet;
533 while ((packet = WaitReturn(timeout)) != NULL) {
534 if (packet->value == (uint32_t)&wifiCb) {
535 if (_debugEn) _debug->println("SYNC!");
536 resetCb = rr;
537 return true;
538 }
539 if (_debugEn) {
540 _debug->print("BAD: ");
541 _debug->println(packet->value);
542 }
543 }
544 // doesn't look like we got a real response
545 resetCb = rr;
546 return false;
547}
548
566 Request();
567}
#define SLIP_ESC
Definition ELClient.cpp:12
#define SLIP_ESC_END
Definition ELClient.cpp:13
#define SLIP_ESC_ESC
Definition ELClient.cpp:14
#define SLIP_END
Definition ELClient.cpp:11
Definitions for ELClient.
@ CMD_RESP_V
Definition ELClient.h:21
@ CMD_WIFI_STATUS
Definition ELClient.h:23
@ CMD_SYNC
Definition ELClient.h:20
@ CMD_RESP_CB
Definition ELClient.h:22
ELClientProtocol _proto
Definition ELClient.h:127
uint16_t crc16Add(unsigned char b, uint16_t acc)
Create CRC for a byte add it to an existing CRC checksum and return the result.
Definition ELClient.cpp:468
ELClientPacket * protoCompletedCb(void)
Process a received SLIP message.
Definition ELClient.cpp:31
uint8_t _protoBuf[128]
Definition ELClient.h:128
boolean Sync(uint32_t timeout=ESP_TIMEOUT)
Synchronize the communication between the MCU and the ESP.
Definition ELClient.cpp:521
void Request(void)
Finish the request.
Definition ELClient.cpp:322
uint16_t crc
Definition ELClient.h:126
ELClientPacket * Process(void)
Handle serial input.
Definition ELClient.cpp:115
void write(uint8_t data)
Send a byte.
Definition ELClient.cpp:154
void DBG(const char *info)
Send debug message over serial debug stream.
Definition ELClient.cpp:419
boolean _debugEn
Definition ELClient.h:125
ELClientPacket * WaitReturn(uint32_t timeout=ESP_TIMEOUT)
Wait for a response from ESP for a given timeout.
Definition ELClient.cpp:444
void(* resetCb)()
Definition ELClient.h:121
Stream * _debug
Definition ELClient.h:85
uint16_t crc16Data(const unsigned char *data, uint16_t len, uint16_t acc)
Create/add CRC for a data buffer.
Definition ELClient.cpp:493
FP< void, void * > wifiCb
Definition ELClient.h:118
void init()
Initialize ELClient protocol.
Definition ELClient.cpp:339
Stream * _serial
Definition ELClient.h:124
ELClient(Stream *serial, Stream *debug)
Initialize ELClient and enable debug output.
Definition ELClient.cpp:404
void GetWifiStatus(void)
Request WiFi status from the ESP.
Definition ELClient.cpp:564
API abstraction for a Function Pointers.
Definition FP.h:136
bool attached()
Definition FP.cpp:34
uint8_t isEsc
Definition ELClient.h:58
uint8_t * buf
Definition ELClient.h:55
uint16_t dataLen
Definition ELClient.h:57
uint16_t bufSize
Definition ELClient.h:56
uint16_t cmd
uint16_t argc
uint32_t value
uint32_t wait