This repository has been archived by the owner on Mar 16, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17
/
esp8266.c
340 lines (321 loc) · 9.36 KB
/
esp8266.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/**
* C library for the ESP8266 WiFi module with a PIC microcontroller
* Copyright (C) 2015 Camil Staps <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*****************************************************************************
*
* File: esp8266.c
* Author: Camil Staps <[email protected]>
* Website: http://github.com/camilstaps/ESP8266_PIC
* Version: 0.1
*
* See: esp8266.h
*
* C library for interfacing the ESP8266 Wi-Fi transceiver module with a PIC18
* microcontroller. Should be used with the XC8 compiler.
*/
#include "esp8266.h"
#include <stdio.h>
#include <string.h>
unsigned char *lit_OK=(unsigned char*)"OK";
/**
* Check if the module is started
*
* This sends the `AT` command to the ESP and waits until it gets a response.
*
* @return true if the module is started, false if something went wrong
*/
bit esp8266_isStarted(void) {
_esp8266_print("AT\r\n");
return (_esp8266_waitResponse() == ESP8266_OK);
}
/**
* Restart the module
*
* This sends the `AT+RST` command to the ESP and waits until there is a
* response.
*
* @return true iff the module restarted properly
*/
bit esp8266_restart(void) {
_esp8266_print("AT+RST\r\n");
if (_esp8266_waitResponse() != ESP8266_OK) {
return false;
}
return (_esp8266_waitResponse() == ESP8266_READY);
}
/**
* Enable / disable command echoing.
*
* Enabling this is useful for debugging: one could sniff the TX line from the
* ESP8266 with his computer and thus receive both commands and responses.
*
* This sends the ATE command to the ESP module.
*
* @param echo whether to enable command echoing or not
*/
void esp8266_echoCmds(bool echo) {
_esp8266_print("ATE");
if (echo) {
_esp8266_putch('1');
} else {
_esp8266_putch('0');
}
_esp8266_print("\r\n");
_esp8266_waitFor(lit_OK);
}
/**
* Set the WiFi mode.
*
* ESP8266_STATION : Station mode
* ESP8266_SOFTAP : Access point mode
*
* This sends the AT+CWMODE command to the ESP module.
*
* @param mode an ORed bitmask of ESP8266_STATION and ESP8266_SOFTAP
*/
void esp8266_mode(unsigned char mode) {
_esp8266_print("AT+CWMODE=");
_esp8266_putch(mode + '0');
_esp8266_print("\r\n");
_esp8266_waitResponse();
}
/**
* Connect to an access point.
*
* This sends the AT+CWJAP command to the ESP module.
*
* @param ssid The SSID to connect to
* @param pass The password of the network
* @return an ESP status code, normally either ESP8266_OK or ESP8266_FAIL
*/
unsigned char esp8266_connect(unsigned char* ssid, unsigned char* pass) {
_esp8266_print("AT+CWJAP=\"");
_esp8266_print(ssid);
_esp8266_print("\",\"");
_esp8266_print(pass);
_esp8266_print("\"\r\n");
return _esp8266_waitResponse();
}
/**
* Disconnect from the access point.
*
* This sends the AT+CWQAP command to the ESP module.
*/
void esp8266_disconnect(void) {
_esp8266_print("AT+CWQAP\r\n");
_esp8266_waitFor(lit_OK);
}
/**
* Store the current local IPv4 address.
*
* This sends the AT+CIFSR command to the ESP module.
*
* The result will not be stored as a string but byte by byte. For example, for
* the IP 192.168.0.1, the value of store_in will be: {0xc0, 0xa8, 0x00, 0x01}.
*
* @param store_in a pointer to an array of the type unsigned char[4]; this
* array will be filled with the local IP.
*/
void esp8266_ip(unsigned char* store_in) {
_esp8266_print("AT+CIFSR\r\n");
unsigned char received;
do {
received = _esp8266_getch();
} while (received < '0' || received > '9');
for (unsigned char i = 0; i < 4; i++) {
store_in[i] = 0;
do {
store_in[i] = 10 * store_in[i] + received - '0';
received = _esp8266_getch();
} while (received >= '0' && received <= '9');
received = _esp8266_getch();
}
_esp8266_waitFor(lit_OK);
}
/**
* Open a TCP or UDP connection.
*
* This sends the AT+CIPSTART command to the ESP module.
*
* @param protocol Either ESP8266_TCP or ESP8266_UDP
* @param ip The IP or hostname to connect to; as a string
* @param port The port to connect to
*
* @return true iff the connection is opened after this.
*/
bit esp8266_start(unsigned char protocol, char* ip, unsigned char port) {
_esp8266_print("AT+CIPSTART=\"");
if (protocol == ESP8266_TCP) {
_esp8266_print("TCP");
} else {
_esp8266_print("UDP");
}
_esp8266_print("\",\"");
_esp8266_print(ip);
_esp8266_print("\",");
unsigned char port_str[5] = "\0\0\0\0";
sprintf(port_str, "%u", port);
_esp8266_print(port_str);
_esp8266_print("\r\n");
if (_esp8266_waitResponse() != ESP8266_OK) {
return 0;
}
if (_esp8266_waitResponse() != ESP8266_LINKED) {
return 0;
}
return 1;
}
// Send data (AT+CIPSEND)
/**
* Send data over a connection.
*
* This sends the AT+CIPSEND command to the ESP module.
*
* @param data The data to send
*
* @return true iff the data was sent correctly.
*/
bit esp8266_send(unsigned char* data) {
unsigned char length_str[6] = "\0\0\0\0\0";
sprintf(length_str, "%u", strlen(data));
_esp8266_print("AT+CIPSEND=");
_esp8266_print(length_str);
_esp8266_print("\r\n");
while (_esp8266_getch() != '>');
_esp8266_print(data);
if (_esp8266_waitResponse() == ESP8266_OK) {
return 1;
}
return 0;
}
/**
* Read a string of data that is sent to the ESP8266.
*
* This waits for a +IPD line from the module. If more bytes than the maximum
* are received, the remaining bytes will be discarded.
*
* @param store_in a pointer to a character array to store the data in
* @param max_length maximum amount of bytes to read in
* @param discard_headers if set to true, we will skip until the first \r\n\r\n,
* for HTTP this means skipping the headers.
*/
void esp8266_receive(unsigned char* store_in, uint16_t max_length, bool discard_headers) {
_esp8266_waitFor((unsigned char*)"+IPD,");
uint16_t length = 0;
unsigned char received = _esp8266_getch();
do {
length = length * 10 + received - '0';
received = _esp8266_getch();
} while (received >= '0' && received <= '9');
if (discard_headers) {
length -= _esp8266_waitFor((unsigned char*)"\r\n\r\n");
}
if (length < max_length) {
max_length = length;
}
/*sprintf(store_in, "%u,%u:%c%c", length, max_length, _esp8266_getch(), _esp8266_getch());
return;*/
uint16_t i;
for (i = 0; i < max_length; i++) {
store_in[i] = _esp8266_getch();
}
store_in[i] = 0;
for (; i < length; i++) {
_esp8266_getch();
}
_esp8266_waitFor(lit_OK);
}
/**
* Output a string to the ESP module.
*
* This is a function for internal use only.
*
* @param ptr A pointer to the string to send.
*/
void _esp8266_print(unsigned const char *ptr) {
while (*ptr != 0) {
_esp8266_putch(*ptr++);
}
}
/**
* Wait until we found a string on the input.
*
* Careful: this will read everything until that string (even if it's never
* found). You may lose important data.
*
* @param string
*
* @return the number of characters read
*/
inline uint16_t _esp8266_waitFor(unsigned char *string) {
unsigned char so_far = 0;
unsigned char received;
uint16_t counter = 0;
do {
received = _esp8266_getch();
counter++;
if (received == string[so_far]) {
so_far++;
} else {
so_far = 0;
}
} while (string[so_far] != 0);
return counter;
}
/**
* Wait until we received the ESP is done and sends its response.
*
* This is a function for internal use only.
*
* Currently the following responses are implemented:
* * OK
* * ready
* * FAIL
* * no change
* * Linked
* * Unlink
*
* Not implemented yet:
* * DNS fail (or something like that)
*
* @return a constant from esp8266.h describing the status response.
*/
inline unsigned char _esp8266_waitResponse(void) {
unsigned char so_far[6] = {0,0,0,0,0,0};
unsigned const char lengths[6] = {2,5,4,9,6,6};
unsigned const char* strings[6] = {"OK", "ready", "FAIL", "no change", "Linked", "Unlink"};
unsigned const char responses[6] = {ESP8266_OK, ESP8266_READY, ESP8266_FAIL, ESP8266_NOCHANGE, ESP8266_LINKED, ESP8266_UNLINK};
unsigned char received;
unsigned char response;
bool continue_loop = true;
while (continue_loop) {
received = _esp8266_getch();
for (unsigned char i = 0; i < 6; i++) {
if (strings[i][so_far[i]] == received) {
so_far[i]++;
if (so_far[i] == lengths[i]) {
response = responses[i];
continue_loop = false;
}
} else {
so_far[i] = 0;
}
}
}
return response;
}