Skip to content

Commit 88ebec6

Browse files
committed
Added ESP8266Interface
- Blocking TCP/UDP
1 parent 04447b6 commit 88ebec6

File tree

10 files changed

+1814
-0
lines changed

10 files changed

+1814
-0
lines changed
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
/* Copyright (c) 2015 ARM Limited
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*
15+
* @section DESCRIPTION
16+
*
17+
* Parser for the AT command syntax
18+
*
19+
*/
20+
21+
#include "ATParser.h"
22+
#include "mbed_debug.h"
23+
24+
25+
// getc/putc handling with timeouts
26+
int ATParser::putc(char c)
27+
{
28+
Timer timer;
29+
timer.start();
30+
31+
while (true) {
32+
if (_serial->writeable()) {
33+
return _serial->putc(c);
34+
}
35+
if (timer.read_ms() > _timeout) {
36+
return -1;
37+
}
38+
}
39+
}
40+
41+
int ATParser::getc()
42+
{
43+
Timer timer;
44+
timer.start();
45+
46+
while (true) {
47+
if (_serial->readable()) {
48+
return _serial->getc();
49+
}
50+
if (timer.read_ms() > _timeout) {
51+
return -1;
52+
}
53+
}
54+
}
55+
56+
void ATParser::flush()
57+
{
58+
while (_serial->readable()) {
59+
_serial->getc();
60+
}
61+
}
62+
63+
64+
// read/write handling with timeouts
65+
int ATParser::write(const char *data, int size)
66+
{
67+
int i = 0;
68+
for ( ; i < size; i++) {
69+
if (putc(data[i]) < 0) {
70+
return -1;
71+
}
72+
}
73+
return i;
74+
}
75+
76+
int ATParser::read(char *data, int size)
77+
{
78+
int i = 0;
79+
for ( ; i < size; i++) {
80+
int c = getc();
81+
if (c < 0) {
82+
return -1;
83+
}
84+
data[i] = c;
85+
}
86+
return i;
87+
}
88+
89+
90+
// printf/scanf handling
91+
int ATParser::vprintf(const char *format, va_list args)
92+
{
93+
if (vsprintf(_buffer, format, args) < 0) {
94+
return false;
95+
}
96+
int i = 0;
97+
for ( ; _buffer[i]; i++) {
98+
if (putc(_buffer[i]) < 0) {
99+
return -1;
100+
}
101+
}
102+
return i;
103+
}
104+
105+
int ATParser::vscanf(const char *format, va_list args)
106+
{
107+
// Since format is const, we need to copy it into our buffer to
108+
// add the line's null terminator and clobber value-matches with asterisks.
109+
//
110+
// We just use the beginning of the buffer to avoid unnecessary allocations.
111+
int i = 0;
112+
int offset = 0;
113+
114+
while (format[i]) {
115+
if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') {
116+
_buffer[offset++] = '%';
117+
_buffer[offset++] = '*';
118+
i++;
119+
} else {
120+
_buffer[offset++] = format[i++];
121+
}
122+
}
123+
124+
// Scanf has very poor support for catching errors
125+
// fortunately, we can abuse the %n specifier to determine
126+
// if the entire string was matched.
127+
_buffer[offset++] = '%';
128+
_buffer[offset++] = 'n';
129+
_buffer[offset++] = 0;
130+
131+
// To workaround scanf's lack of error reporting, we actually
132+
// make two passes. One checks the validity with the modified
133+
// format string that only stores the matched characters (%n).
134+
// The other reads in the actual matched values.
135+
//
136+
// We keep trying the match until we succeed or some other error
137+
// derails us.
138+
int j = 0;
139+
140+
while (true) {
141+
// Ran out of space
142+
if (j+1 >= _buffer_size - offset) {
143+
return false;
144+
}
145+
// Recieve next character
146+
int c = getc();
147+
if (c < 0) {
148+
return -1;
149+
}
150+
_buffer[offset + j++] = c;
151+
_buffer[offset + j] = 0;
152+
153+
// Check for match
154+
int count = -1;
155+
sscanf(_buffer+offset, _buffer, &count);
156+
157+
// We only succeed if all characters in the response are matched
158+
if (count == j) {
159+
// Store the found results
160+
vsscanf(_buffer+offset, format, args);
161+
return j;
162+
}
163+
}
164+
}
165+
166+
167+
// Command parsing with line handling
168+
bool ATParser::vsend(const char *command, va_list args)
169+
{
170+
// Create and send command
171+
if (vsprintf(_buffer, command, args) < 0) {
172+
return false;
173+
}
174+
for (int i = 0; _buffer[i]; i++) {
175+
if (putc(_buffer[i]) < 0) {
176+
return false;
177+
}
178+
}
179+
180+
// Finish with newline
181+
for (int i = 0; _delimiter[i]; i++) {
182+
if (putc(_delimiter[i]) < 0) {
183+
return false;
184+
}
185+
}
186+
187+
debug_if(dbg_on, "AT> %s\r\n", _buffer);
188+
return true;
189+
}
190+
191+
bool ATParser::vrecv(const char *response, va_list args)
192+
{
193+
// Iterate through each line in the expected response
194+
while (response[0]) {
195+
// Since response is const, we need to copy it into our buffer to
196+
// add the line's null terminator and clobber value-matches with asterisks.
197+
//
198+
// We just use the beginning of the buffer to avoid unnecessary allocations.
199+
int i = 0;
200+
int offset = 0;
201+
202+
while (response[i]) {
203+
if (memcmp(&response[i+1-_delim_size], _delimiter, _delim_size) == 0) {
204+
i++;
205+
break;
206+
} else if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') {
207+
_buffer[offset++] = '%';
208+
_buffer[offset++] = '*';
209+
i++;
210+
} else {
211+
_buffer[offset++] = response[i++];
212+
}
213+
}
214+
215+
// Scanf has very poor support for catching errors
216+
// fortunately, we can abuse the %n specifier to determine
217+
// if the entire string was matched.
218+
_buffer[offset++] = '%';
219+
_buffer[offset++] = 'n';
220+
_buffer[offset++] = 0;
221+
222+
// To workaround scanf's lack of error reporting, we actually
223+
// make two passes. One checks the validity with the modified
224+
// format string that only stores the matched characters (%n).
225+
// The other reads in the actual matched values.
226+
//
227+
// We keep trying the match until we succeed or some other error
228+
// derails us.
229+
int j = 0;
230+
231+
while (true) {
232+
// Recieve next character
233+
int c = getc();
234+
if (c < 0) {
235+
return false;
236+
}
237+
_buffer[offset + j++] = c;
238+
_buffer[offset + j] = 0;
239+
240+
// Check for match
241+
int count = -1;
242+
sscanf(_buffer+offset, _buffer, &count);
243+
244+
// We only succeed if all characters in the response are matched
245+
if (count == j) {
246+
debug_if(dbg_on, "AT= %s\r\n", _buffer+offset);
247+
// Reuse the front end of the buffer
248+
memcpy(_buffer, response, i);
249+
_buffer[i] = 0;
250+
251+
// Store the found results
252+
vsscanf(_buffer+offset, _buffer, args);
253+
254+
// Jump to next line and continue parsing
255+
response += i;
256+
break;
257+
}
258+
259+
// Clear the buffer when we hit a newline or ran out of space
260+
// running out of space usually means we ran into binary data
261+
if (j+1 >= _buffer_size - offset ||
262+
strcmp(&_buffer[offset + j-_delim_size], _delimiter) == 0) {
263+
264+
debug_if(dbg_on, "AT< %s", _buffer+offset);
265+
j = 0;
266+
}
267+
}
268+
}
269+
270+
return true;
271+
}
272+
273+
274+
// Mapping to vararg functions
275+
int ATParser::printf(const char *format, ...)
276+
{
277+
va_list args;
278+
va_start(args, format);
279+
int res = vprintf(format, args);
280+
va_end(args);
281+
return res;
282+
}
283+
284+
int ATParser::scanf(const char *format, ...)
285+
{
286+
va_list args;
287+
va_start(args, format);
288+
int res = vscanf(format, args);
289+
va_end(args);
290+
return res;
291+
}
292+
293+
bool ATParser::send(const char *command, ...)
294+
{
295+
va_list args;
296+
va_start(args, command);
297+
bool res = vsend(command, args);
298+
va_end(args);
299+
return res;
300+
}
301+
302+
bool ATParser::recv(const char *response, ...)
303+
{
304+
va_list args;
305+
va_start(args, response);
306+
bool res = vrecv(response, args);
307+
va_end(args);
308+
return res;
309+
}

0 commit comments

Comments
 (0)