Skip to content

Commit cc460d8

Browse files
committed
[esp8266] Added mechanism for handling out-of-band AT commands
Out-of-band AT commands from device are handled and buffered via callback. Adopted in ESP8266. Fixes #348
1 parent 3b6d076 commit cc460d8

File tree

4 files changed

+126
-10
lines changed

4 files changed

+126
-10
lines changed

ESP8266/ATParser/ATParser.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,19 @@ bool ATParser::vrecv(const char *response, va_list args)
237237
_buffer[offset + j++] = c;
238238
_buffer[offset + j] = 0;
239239

240+
// Check for oob data
241+
for (int k = 0; k < _oobs.size(); k++) {
242+
if (j == _oobs[k].len && memcmp(
243+
_oobs[k].prefix, _buffer+offset, _oobs[k].len) == 0) {
244+
debug_if(dbg_on, "AT! %s\r\n", _oobs[k].prefix);
245+
_oobs[k].cb();
246+
247+
// oob may have corrupted non-reentrant buffer,
248+
// so we need to set it up again
249+
return vrecv(response, args);
250+
}
251+
}
252+
240253
// Check for match
241254
int count = -1;
242255
sscanf(_buffer+offset, _buffer, &count);
@@ -307,3 +320,10 @@ bool ATParser::recv(const char *response, ...)
307320
va_end(args);
308321
return res;
309322
}
323+
324+
325+
// oob registration
326+
void ATParser::oob(const char *prefix, Callback<void()> cb)
327+
{
328+
_oobs.push_back((struct oob){strlen(prefix), prefix, cb});
329+
}

ESP8266/ATParser/ATParser.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020

2121
#include "mbed.h"
2222
#include <cstdarg>
23+
#include <vector>
2324
#include "BufferedSerial.h"
25+
#include "Callback.h"
2426

2527

2628
/**
@@ -54,6 +56,13 @@ class ATParser
5456
int _delim_size;
5557
bool dbg_on;
5658

59+
struct oob {
60+
unsigned len;
61+
const char *prefix;
62+
mbed::Callback<void()> cb;
63+
};
64+
std::vector<oob> _oobs;
65+
5766
public:
5867
/**
5968
* Constructor
@@ -193,6 +202,28 @@ class ATParser
193202
int scanf(const char *format, ...);
194203
int vscanf(const char *format, va_list args);
195204

205+
/**
206+
* Attach a callback for out-of-band data
207+
*
208+
* @param prefix string on when to initiate callback
209+
* @param func callback to call when string is read
210+
* @note out-of-band data is only processed during a scanf call
211+
*/
212+
void oob(const char *prefix, mbed::Callback<void()> func);
213+
214+
/**
215+
* Attach a callback for out-of-band data
216+
*
217+
* @param prefix string on when to initiate callback
218+
* @param obj pointer to object to call member function on
219+
* @param method callback to call when string is read
220+
* @note out-of-band data is only processed during a scanf call
221+
*/
222+
template <typename T, typename M>
223+
void oob(const char *prefix, T *obj, M method) {
224+
return oob(prefix, mbed::Callback<void()>(obj, method));
225+
}
226+
196227
/**
197228
* Flushes the underlying stream
198229
*/

ESP8266/ESP8266.cpp

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
ESP8266::ESP8266(PinName tx, PinName rx, bool debug)
2020
: _serial(tx, rx, 1024), _parser(_serial)
21+
, _packets(0), _packets_end(&_packets)
2122
{
2223
_serial.baud(115200);
2324
_parser.debugOn(debug);
@@ -30,11 +31,15 @@ bool ESP8266::startup(int mode)
3031
return false;
3132
}
3233

33-
return reset()
34+
bool success = reset()
3435
&& _parser.send("AT+CWMODE=%d", mode)
3536
&& _parser.recv("OK")
3637
&& _parser.send("AT+CIPMUX=1")
3738
&& _parser.recv("OK");
39+
40+
_parser.oob("+IPD", this, &ESP8266::_packet_handler);
41+
42+
return success;
3843
}
3944

4045
bool ESP8266::reset(void)
@@ -123,20 +128,72 @@ bool ESP8266::send(int id, const void *data, uint32_t amount)
123128
return false;
124129
}
125130

126-
int32_t ESP8266::recv(int id, void *data, uint32_t amount)
131+
void ESP8266::_packet_handler()
127132
{
128-
uint32_t recv_amount;
129-
int recv_id;
133+
int id;
134+
uint32_t amount;
130135

131-
if (!(_parser.recv("+IPD,%d,%d:", &recv_id, &recv_amount)
132-
&& recv_id == id
133-
&& recv_amount <= amount
134-
&& _parser.read((char*)data, recv_amount)
136+
// parse out the packet
137+
if (!_parser.recv(",%d,%d:", &id, &amount)) {
138+
return;
139+
}
140+
141+
struct packet *packet = (struct packet*)malloc(
142+
sizeof(struct packet) + amount);
143+
if (!packet) {
144+
return;
145+
}
146+
147+
packet->id = id;
148+
packet->len = amount;
149+
packet->next = 0;
150+
151+
if (!(_parser.read((char*)(packet + 1), amount)
135152
&& _parser.recv("OK"))) {
136-
return -1;
153+
free(packet);
154+
return;
137155
}
138156

139-
return recv_amount;
157+
// append to packet list
158+
*_packets_end = packet;
159+
_packets_end = &packet->next;
160+
}
161+
162+
int32_t ESP8266::recv(int id, void *data, uint32_t amount)
163+
{
164+
while (true) {
165+
// check if any packets are ready for us
166+
for (struct packet **p = &_packets; *p; p = &(*p)->next) {
167+
if ((*p)->id == id) {
168+
struct packet *q = *p;
169+
170+
if (q->len <= amount) { // Return and remove full packet
171+
memcpy(data, q+1, q->len);
172+
173+
if (_packets_end == &(*p)->next) {
174+
_packets_end = p;
175+
}
176+
*p = (*p)->next;
177+
178+
uint32_t len = q->len;
179+
free(q);
180+
return len;
181+
} else { // return only partial packet
182+
memcpy(data, q+1, amount);
183+
184+
q->len -= amount;
185+
memmove(q+1, (uint8_t*)(q+1) + amount, q->len);
186+
187+
return amount;
188+
}
189+
}
190+
}
191+
192+
// Wait for inbound packet
193+
if (!_parser.recv("OK")) {
194+
return -1;
195+
}
196+
}
140197
}
141198

142199
bool ESP8266::close(int id)

ESP8266/ESP8266.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@ class ESP8266
166166
BufferedSerial _serial;
167167
ATParser _parser;
168168

169+
struct packet {
170+
struct packet *next;
171+
int id;
172+
uint32_t len;
173+
// data follows
174+
} *_packets, **_packets_end;
175+
void _packet_handler();
176+
169177
char _ip_buffer[16];
170178
char _mac_buffer[18];
171179
};

0 commit comments

Comments
 (0)