1////////////////////////////////////////////////////////////////////////////////
2// //
3// This software is supplied under the terms of a license agreement or //
4// nondisclosure agreement with Mitov Software and may not be copied //
5// or disclosed except in accordance with the terms of that agreement. //
6// Copyright(c) 2002-2016 Mitov Software. All Rights Reserved. //
7// //
8////////////////////////////////////////////////////////////////////////////////
9
10#ifndef _MITOV_ESP8266_h
11#define _MITOV_ESP8266_h
12
13#include <Mitov.h>
14#include <Mitov_BasicEthernet.h>
15#include <Mitov_StringPrint.h>
16
17//#define __ESP8266__DEBUG__
18
19namespace Mitov
20{
21 class ESP8266;
22//---------------------------------------------------------------------------
23 class ESP8266RemoteAccessPoint
24 {
25 public:
26 bool Enabled = true;
27 String SSID;
28 String Password;
29 };
30//---------------------------------------------------------------------------
31 class ESP8266Encription
32 {
33 public:
34 bool WPA = false;
35 bool WPA2 = false;
36 };
37//---------------------------------------------------------------------------
38 class ESP8266AccessPoint
39 {
40 public:
41 bool Enabled = true;
42 String SSID;
43 String Password;
44
45 unsigned long Channel = 1;
46 ESP8266Encription Encription;
47 };
48//---------------------------------------------------------------------------
49 class BasicESP8266Socket : public Mitov::BasicSocket
50 {
51 typedef Mitov::BasicSocket inherited;
52
53 protected:
54 ESP8266 &FModule;
55 bool FRunning = false;
56
57 protected:
58 BufferPrint FStringPrint;
59
60 public:
61 virtual bool IsEnabled()
62 {
63 return Enabled && FRunning; //FModule.Enabled;
64 }
65
66 virtual Print *GetPrint()
67 {
68 return &FStringPrint;
69 }
70
71 virtual void BeginPacket()
72 {
73 FStringPrint.Value.clear();
74 }
75
76 virtual void DataReceived( int connectionId, unsigned char AData ) = 0;
77
78 public:
79 BasicESP8266Socket( ESP8266 &AModule );
80 };
81//---------------------------------------------------------------------------
82 class ESP8266 : public OpenWire::Component
83 {
84 typedef OpenWire::Component inherited;
85
86 public:
87 OpenWire::SourcePin AccessPointAddressOutputPin;
88 OpenWire::SourcePin AccessPointMACOutputPin;
89
90 OpenWire::SourcePin StationAddressOutputPin;
91 OpenWire::SourcePin StationMACOutputPin;
92
93 public:
94 ESP8266AccessPoint AccessPoint;
95 Mitov::SimpleObjectList<ESP8266RemoteAccessPoint*> RemoteAccessPoints;
96
97 public:
98 Mitov::SimpleList<BasicESP8266Socket*> Sockets;
99
100 protected:
101 Mitov::BasicSerialPort &FSerial;
102
103 protected:
104 Mitov::BasicESP8266Socket *FServerInstance;
105
106 public:
107 Mitov::BasicESP8266Socket *FConnections[ 4 ];
108
109 int FReadLength = 0;
110 int FReadConnectionId = 0;
111
112 public:
113 bool AssignServerID( BasicESP8266Socket *ASocket )
114 {
115 bool AResult = false;
116 for( int i = 0; i < 4; ++i )
117 if( ! FConnections[ i ] )
118 {
119 FConnections[ i ] = ASocket;
120 FServerInstance = ASocket;
121 AResult = true;
122 }
123
124 return AResult;
125 }
126
127 void ReleaseServerID( BasicESP8266Socket *ASocket )
128 {
129 if( FServerInstance == ASocket )
130 FServerInstance = NULL;
131
132 for( int i = 0; i < 4; ++i )
133 if( FConnections[ i ] == ASocket )
134 FConnections[ i ] = NULL;
135 }
136
137 bool AssignConnectionID( BasicESP8266Socket *ASocket, int &AID )
138 {
139 for( int i = 0; i < 4; ++i )
140 if( ! FConnections[ i ] )
141 {
142 FConnections[ i ] = ASocket;
143 AID = i;
144 return true;
145 }
146
147 return false;
148 }
149
150 void ReleaseConnectionID( int AID )
151 {
152 FConnections[ AID ] = FServerInstance;
153 }
154
155 void SendDirect(String data )
156 {
157#ifdef __ESP8266__DEBUG__
158 Serial.println( data );
159#endif
160 FSerial.GetStream().print( data );
161 WaitSentOK( 2000 );
162 }
163
164 void SendDirect( uint8_t *AData, int ASize )
165 {
166#ifdef __ESP8266__DEBUG__
167 Serial.write( AData, ASize );
168#endif
169 FSerial.GetStream().write( AData, ASize );
170 WaitSentOK( 2000 );
171 }
172
173 void WaitSentOK( const int timeout )
174 {
175 String response = "";
176 long int time = millis();
177
178 while( timeout > millis() - time)
179 {
180 while(FSerial.GetStream().available())
181 {
182 // The esp has data so collecti it
183 char c = FSerial.GetStream().read(); // read the next character.
184 response += c;
185 }
186
187 if( response.indexOf( "SEND OK\r\n" ) >= 0 )
188 break;
189
190 }
191 }
192
193 String SendData(String command, String response_key, const int timeout)
194 {
195 String response = "";
196
197#ifdef __ESP8266__DEBUG__
198 Serial.println( command );
199#endif
200 FSerial.GetStream().print( command + "\r\n" ); // send the read character to the esp8266
201
202 long int time = millis();
203
204 while( timeout > millis() - time)
205 {
206 while(FSerial.GetStream().available())
207 {
208 // The esp has data so collecti it
209 char c = FSerial.GetStream().read(); // read the next character.
210 response += c;
211 }
212
213 if( response.indexOf( response_key ) >= 0 )
214 break;
215
216 }
217
218#ifdef __ESP8266__DEBUG__
219 Serial.println( response );
220#endif
221 return response;
222 }
223
224 bool SendData(String command, const int timeout, String &AResponse )
225 {
226 AResponse = "";
227
228#ifdef __ESP8266__DEBUG__
229 Serial.println( command );
230#endif
231
232 FSerial.GetStream().print( command + "\r\n" ); // send the read character to the esp8266
233
234 long int time = millis();
235
236 while( timeout > millis() - time)
237 {
238 while(FSerial.GetStream().available())
239 {
240 // The esp has data so collecti it
241 char c = FSerial.GetStream().read(); // read the next character.
242 AResponse += c;
243 }
244
245 if( AResponse.indexOf( "\r\nOK\r\n" ) >= 0 )
246 {
247#ifdef __ESP8266__DEBUG__
248 Serial.println( AResponse );
249#endif
250 return true;
251 }
252
253 if( AResponse.indexOf( "\r\nERROR\r\n" ) >= 0 )
254 {
255#ifdef __ESP8266__DEBUG__
256 Serial.println( AResponse );
257#endif
258 return false;
259 }
260
261 if( AResponse.indexOf( "\r\nFAIL\r\n" ) >= 0 )
262 {
263#ifdef __ESP8266__DEBUG__
264 Serial.println( AResponse );
265#endif
266 return false;
267 }
268
269 }
270
271#ifdef __ESP8266__DEBUG__
272 Serial.println( AResponse );
273#endif
274 return false;
275 }
276
277 bool SendData( String command, const int timeout )
278 {
279 String AResponse;
280 return SendData( command, timeout, AResponse );
281 }
282
283 protected:
284 virtual void SystemStart()
285 {
286 inherited::SystemStart();
287
288#ifdef __ESP8266__DEBUG__
289 Serial.println( "SystemStart" );
290#endif
291 SendData( "AT+RST", "\r\nready\r\n", 5000 );
292// String AResponse = SendData( "AT+RST", "\r\nready\r\n", 5000 );
293// Serial.println( AResponse );
294
295#ifdef __ESP8266__DEBUG__
296 Serial.println( "INIT" );
297#endif
298
299 int AMode = 0;
300
301 for( Mitov::SimpleObjectList<ESP8266RemoteAccessPoint*>::iterator Iter = RemoteAccessPoints.begin(); Iter != RemoteAccessPoints.end(); ++Iter )
302 if((* Iter)->Enabled )
303 {
304 AMode = 1;
305 break;
306 }
307
308 if( AMode == 0 || AccessPoint.Enabled )
309 AMode |= 2; // Set it as access point so others can connect
310
311// AMode = 3;
312 SendData( "AT+CWMODE=" + String( AMode ), 5000 );
313
314// Serial.println( "TTT" );
315// return;
316
317 if( AccessPoint.Enabled )
318// if( AccessPoint.Encription )
319 {
320 String ASSID;
321 if( AccessPoint.SSID != "" )
322 ASSID = AccessPoint.SSID;
323
324 else
325 ASSID = "Arduino";
326
327 String AEncoding;
328 if( AccessPoint.Encription.WPA )
329 {
330 if( AccessPoint.Encription.WPA2 )
331 AEncoding = "4";
332
333 else
334 AEncoding = "2";
335 }
336
337 else
338 {
339 if( AccessPoint.Encription.WPA2 )
340 AEncoding = "3";
341
342 else
343 AEncoding = "0";
344 }
345
346 SendData( "AT+CWSAP=\"" + ASSID + "\",\"" + AccessPoint.Password + "\"," + AccessPoint.Channel + "," + AEncoding, 1000 );
347 }
348
349 for( Mitov::SimpleObjectList<ESP8266RemoteAccessPoint*>::iterator Iter = RemoteAccessPoints.begin(); Iter != RemoteAccessPoints.end(); ++Iter )
350 if((* Iter)->Enabled )
351 if((* Iter)->SSID != "" )
352 if( SendData( "AT+CWJAP=\"" + (* Iter)->SSID + "\",\"" + (* Iter)->Password + "\"", 20000 ))
353 break;
354
355 if( AccessPointAddressOutputPin.IsConnected() || AccessPointMACOutputPin.IsConnected() || StationAddressOutputPin.IsConnected() || StationMACOutputPin.IsConnected() )
356 {
357// Serial.println( "ADDRESS:" );
358 String AResponse = SendData( "AT+CIFSR", "\r\nOK\r\n",1000 );
359#ifdef __ESP8266__DEBUG__
360 Serial.println( AResponse );
361#endif
362
363 int AAddressPos = AResponse.indexOf( "+CIFSR:APIP,\"" );
364
365 int AAddressEndPos;
366 if( AAddressPos >= 0 )
367 {
368 AAddressEndPos = AResponse.indexOf( "\"", AAddressPos + 13 );
369 if( AAddressEndPos >= 0 )
370 {
371 String Addresses = AResponse.substring( AAddressPos + 13, AAddressEndPos );
372 AccessPointAddressOutputPin.Notify( (void *)Addresses.c_str() );
373 }
374
375 else
376 AAddressEndPos = 0;
377
378 }
379
380 else
381 AAddressEndPos = 0;
382
383 AAddressPos = AResponse.indexOf( "+CIFSR:APMAC,\"", AAddressEndPos );
384 if( AAddressPos >= 0 )
385 {
386 AAddressEndPos = AResponse.indexOf( "\"", AAddressPos + 14 );
387 if( AAddressEndPos >= 0 )
388 {
389 String Addresses = AResponse.substring( AAddressPos + 14, AAddressEndPos );
390 AccessPointMACOutputPin.Notify( (void *)Addresses.c_str() );
391 }
392
393 else
394 AAddressEndPos = 0;
395
396 }
397 else
398 AAddressEndPos = 0;
399
400 AAddressPos = AResponse.indexOf( "+CIFSR:STAIP,\"", AAddressEndPos );
401 if( AAddressPos >= 0 )
402 {
403 AAddressEndPos = AResponse.indexOf( "\"", AAddressPos + 14 );
404 if( AAddressEndPos >= 0 )
405 {
406 String Addresses = AResponse.substring( AAddressPos + 14, AAddressEndPos );
407 StationAddressOutputPin.Notify( (void *)Addresses.c_str() );
408 }
409
410 else
411 AAddressEndPos = 0;
412
413 }
414 else
415 AAddressEndPos = 0;
416
417 AAddressPos = AResponse.indexOf( "+CIFSR:STAMAC,\"", AAddressEndPos );
418 if( AAddressPos >= 0 )
419 {
420 AAddressEndPos = AResponse.indexOf( "\"", AAddressPos + 15 );
421 if( AAddressEndPos >= 0 )
422 {
423 String Addresses = AResponse.substring( AAddressPos + 15, AAddressEndPos );
424 StationMACOutputPin.Notify( (void *)Addresses.c_str() );
425 }
426
427 else
428 AAddressEndPos = 0;
429
430 }
431 else
432 AAddressEndPos = 0;
433
434 }
435
436 SendData( "AT+CIPMUX=1",1000 );
437 }
438
439 virtual void SystemLoopBegin( unsigned long currentMicros )
440 {
441 if( FSerial.GetStream().available() )
442 {
443#ifdef __ESP8266__DEBUG__
444// Serial.println( "AVALIABLE" );
445#endif
446 if( ! FReadLength )
447 if(FSerial.GetStream().find("+IPD,"))
448 {
449#ifdef __ESP8266__DEBUG__
450 Serial.println( "DATA" );
451#endif
452// int connectionId = FSerial.GetStream().read() - '0';
453 String AIDStr = FSerial.GetStream().readStringUntil( ',' );
454 FReadConnectionId = AIDStr.toInt();
455#ifdef __ESP8266__DEBUG__
456 Serial.println( AIDStr );
457 Serial.println( FReadConnectionId );
458#endif
459// FSerial.GetStream().find("," ); // Skip ','
460// FSerial.GetStream().read(); // Skip ','
461 String ALengthStr = FSerial.GetStream().readStringUntil( ':' );
462#ifdef __ESP8266__DEBUG__
463 Serial.println( "Length = " + ALengthStr );
464#endif
465 FReadLength = ALengthStr.toInt();
466 }
467
468 if( FReadLength )
469 if( FReadConnectionId >= 0 && FReadConnectionId < 4 )
470 {
471 while( FReadLength )
472 {
473 if( ! FSerial.GetStream().available() )
474 break;
475
476 int AData = FSerial.GetStream().read();
477//#ifdef __ESP8266__DEBUG__
478// Serial.println( (char)AData );
479//#endif
480 if( FConnections[ FReadConnectionId ] )
481 FConnections[ FReadConnectionId ]->DataReceived( FReadConnectionId, AData );
482
483 --FReadLength;
484 }
485 }
486
487 }
488
489 inherited::SystemLoopBegin( currentMicros );
490 }
491
492 public:
493 ESP8266( Mitov::BasicSerialPort &ASerial ) :
494 FSerial( ASerial )
495 {
496 memset( FConnections, 0, 4 * sizeof( FConnections[ 0 ] ) );
497 }
498
499 };
500//---------------------------------------------------------------------------
501 class ESP8266TCPServerSocket : public BasicESP8266Socket
502 {
503 typedef BasicESP8266Socket inherited;
504
505// EthernetServer *FServer;
506// EthernetClient FClient;
507
508 int FClientCurrentID = -1;
509
510 protected:
511 virtual void StartSocket()
512 {
513#ifdef __ESP8266__DEBUG__
514 Serial.println( "SERVER::StartSocket" );
515#endif
516// if( FModule.AssignConnectionID( this ) )
517 if( FModule.AssignServerID( this ) )
518 {
519 FModule.SendData( "AT+CIPSERVER=1," + String( Port ), 2000 );
520 FRunning = true;
521 }
522
523 }
524
525/*
526 virtual void SystemLoopBegin( unsigned long currentMicros )
527 {
528 inherited::SystemLoopBegin( currentMicros );
529 }
530*/
531 virtual void DataReceived( int connectionId, unsigned char AData )
532 {
533#ifdef __ESP8266__DEBUG__
534 Serial.print( "RECEIVED: " );
535 Serial.println( connectionId );
536#endif
537 FClientCurrentID = connectionId;
538 OutputPin.Notify( &AData );
539// FClientCurrentID = -1;
540 }
541
542 public:
543 virtual void EndPacket()
544 {
545 if( FStringPrint.Value.size() == 0 )
546 return;
547
548 if( FClientCurrentID >= 0 )
549 {
550 if( FModule.SendData( "AT+CIPSEND=" + String( FClientCurrentID ) + "," + String( FStringPrint.Value.size()), "\r\n> ", 2000 ))
551 FModule.SendDirect( (uint8_t *)FStringPrint.Value, FStringPrint.Value.size() );
552
553// Serial.println( FStringPrint.Value );
554 }
555
556 else
557 {
558/*
559 for( int i = 0; i < 4; ++ i )
560 if( FModule.FConnections[ i ] == this )
561 {
562 if( FModule.SendData( "AT+CIPSEND=" + String( i ) + "," + String( FStringPrint.Value.size()), "\r\n> ", 2000 ))
563 FModule.SendDirect( (uint8_t *)FStringPrint.Value, FStringPrint.Value.size() );
564
565 }
566*/
567 }
568
569// FStringPrint.Value.clear();
570 }
571
572 public:
573 virtual void StopSocket()
574 {
575 if( FRunning )
576 {
577 FModule.SendData( "AT+CIPSERVER=0," + String( Port ), 2000 );
578 FModule.ReleaseServerID( this );
579 FRunning = false;
580 }
581 }
582
583 public:
584 using inherited::inherited;
585
586 };
587//---------------------------------------------------------------------------
588 class ESP8266TCPClientSocket : public BasicESP8266Socket
589 {
590 typedef BasicESP8266Socket inherited;
591
592 public:
593 String URL;
594 int FID;
595
596 protected:
597 virtual void StartSocket()
598 {
599#ifdef __ESP8266__DEBUG__
600 Serial.println( "CLIENT::StartSocket" );
601#endif
602 if( FModule.AssignConnectionID( this, FID ) )
603 {
604 FModule.SendData( "AT+CIPSTART=" + String( FID ) +",\"TCP\",\"" + URL + "\"," + String( Port ), 2000 );
605 FRunning = true;
606 }
607
608// Serial.println( "StartSocket" );
609 }
610
611 virtual void StopSocket()
612 {
613 if( FRunning )
614 {
615 FModule.ReleaseConnectionID( FID );
616 FModule.SendData( "AT+CIPCLOSE=" + String( FID ), 2000 );
617 FRunning = false;
618 }
619// FClient.stop();
620 }
621
622 virtual void DataReceived( int connectionId, unsigned char AData )
623 {
624 OutputPin.Notify( &AData );
625 }
626
627 public:
628 virtual void EndPacket()
629 {
630 if( FStringPrint.Value.size() == 0 )
631 return;
632
633 if( FModule.SendData( "AT+CIPSEND=" + String( FID ) + "," + String( FStringPrint.Value.size()), "\r\n> ", 2000 ))
634 FModule.SendDirect( (uint8_t *)FStringPrint.Value, FStringPrint.Value.size() );
635
636// FStringPrint.Value.clear();
637 }
638
639 public:
640/*
641 virtual void SystemLoopBegin( unsigned long currentMicros )
642 {
643 inherited::SystemLoopBegin( currentMicros );
644 }
645*/
646 public:
647 using inherited::inherited;
648
649 };
650//---------------------------------------------------------------------------
651//---------------------------------------------------------------------------
652//---------------------------------------------------------------------------
653//---------------------------------------------------------------------------
654 BasicESP8266Socket::BasicESP8266Socket( ESP8266 &AModule ) :
655 FModule( AModule )
656 {
657 AModule.Sockets.push_back( this );
658 }
659//---------------------------------------------------------------------------
660}
661
662#endif