Skip to content

Instantly share code, notes, and snippets.

@xesscorp
Created December 19, 2014 17:19
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save xesscorp/0f3546c674fb7e1d34ac to your computer and use it in GitHub Desktop.
Save xesscorp/0f3546c674fb7e1d34ac to your computer and use it in GitHub Desktop.
This program issues commands to an ESP8266 Wifi module in order to receive an HTML page from a website.
///////////////////////////////////////////////////////////////////////////////////////
// This program uses the ESP8266 Wifi module to access a webpage. It's an adaptation of
// the program discussed at http://hackaday.io/project/3072/instructions
// and shown here http://dunarbin.com/esp8266/retroBrowser.ino .
//
// This program was ported to the ZPUino 2.0, a softcore processor that runs on an FPGA
// and emulates an Arduino.
//
// This program works with version 0018000902 of the ESP8266 firmware.
///////////////////////////////////////////////////////////////////////////////////////
#define SSID "XESS2"
#define PASS "29568208" // ESP8266 works with WPA2-PSK (AES) passwords.
//#define DEST_HOST "retro.hackaday.com"
//#define DEST_PAGE "/"
//#define DEST_IP "192.254.235.21"
#define DEST_HOST "www.xess.com"
#define DEST_PAGE "/static/media/pages/xess_esp8266.html"
#define DEST_IP "192.241.200.6"
#define DEST_PORT 80
#define TIMEOUT 10000 // mS
#define CONTINUE false
#define HALT true
#define DO_ECHO true
#define NO_ECHO false
#define CONNECTION_TRIES 5
#define ECHO_COMMANDS // Un-comment to echo AT+ commands to serial monitor.
unsigned long deadline; // Global time deadline for receiving characters.
// Print error message and loop stop.
void errorHalt(String msg)
{
Serial.println(msg);
Serial.println("HALT");
while(true);
}
// Wait until a char is received from the ESP8266. Then return it.
char getChar(bool checkDeadline=false)
{
while(Serial1.available() == false)
if(checkDeadline == true)
{
if(millis() >= deadline)
return 0;
}
return Serial1.read();
}
// Buffer used to compare strings against the output from the ESP8266.
#define CB_SIZE 20
char comp_buffer[CB_SIZE] = {0,}; // Fill buffer with string terminator.
// Get char from ESP8266 and also shift it into the comparison buffer.
char getCharAndBuffer(bool checkDeadline=false)
{
char b = getChar(checkDeadline);
char *cb_src, *cb_dst;
cb_src = comp_buffer+1;
cb_dst = comp_buffer;
for(int i=1; i<CB_SIZE-1; i++)
*cb_dst++ = *cb_src++;
*cb_dst = b;
return b;
}
// Compare the string against the newest contents of the buffer.
boolean cb_match(String &s)
{
return strcmp(s, comp_buffer + CB_SIZE - 1 - s.length()) == 0; // Return true on match.
}
// Read characters from ESP8266 module and echo to serial until keyword occurs or timeout.
boolean echoFind(String keyword, boolean do_echo)
{
// Fail if the target string has not been sent by deadline.
deadline = millis() + TIMEOUT;
while(millis() < deadline)
{
char ch = getCharAndBuffer(true);
if(do_echo)
Serial.write(ch);
if(cb_match(keyword))
return true;
}
return false; // Timed out
}
// Echo module output until 3 newlines encountered.
// (Used when we're indifferent to "OK" vs. "no change" responses.)
void echoSkip()
{
echoFind("\n", DO_ECHO); // Search for nl at end of command echo
echoFind("\n", DO_ECHO); // Search for 2nd nl at end of response.
echoFind("\n", DO_ECHO); // Search for 3rd nl at end of blank line.
}
// Send a command to the module and wait for acknowledgement string
// (or flush module output if no ack specified).
// Echoes all data received to the serial monitor.
boolean echoCommand(String cmd, String ack, boolean halt_on_fail)
{
// Send the command to the ESP8266.
Serial1.print(cmd);
Serial1.write("\015\012"); // Append carriage-return+linefeed to commands.
#ifdef ECHO_COMMANDS
Serial.println("\n\n\r--------------------------------------");
Serial.println("COMMAND: " + cmd + "\n");
#endif
// If no ack response specified, skip all available module output.
if (strlen(ack) == 0)
echoSkip();
else
{
// Otherwise wait for ack.
if (!echoFind(ack, DO_ECHO)) // timed out waiting for ack string
{
if (halt_on_fail)
errorHalt(cmd + " failed");// Critical failure halt.
else
return false; // Let the caller handle it.
}
}
return true; // ack blank or ack found
}
// Data packets have the format "+IPD,0,1024:lwkjfwsnv....". This routine gets
// the second number preceding the ":" that indicates the number of characters
// in the packet.
int getPacketLength()
{
while(getChar() != ',')
;
char len[10];
for(int i=0; i<10; i++)
{
char c = getChar();
if(c == ':')
{
len[i] = 0; // Terminate string.
break;
}
len[i] = c;
}
return atoi(len);
}
// Echo a received Wifi packet to the PC.
void echoPacket()
{
if(echoFind("+IPD,", NO_ECHO))
{
for(int l = getPacketLength(); l>0; l--)
Serial.write(getChar());
}
}
// Connect to the specified wireless network.
boolean connectWiFi(String ssid, String pwd)
{
String cmd = "AT+CWJAP=\"" + ssid + "\",\"" + pwd + "\"";
if (echoCommand(cmd, "OK", CONTINUE)) // Join Access Point
{
Serial.println("\nConnected to WiFi.");
return true;
}
else
{
Serial.println("\nConnection to WiFi failed.");
return false;
}
}
// Establish a TCP link to a given IP address and port.
boolean establishTcpLink(String ip, int port)
{
String cmd = "AT+CIPSTART=0,\"TCP\",\"" + ip + "\"," + port;
return echoCommand(cmd, "OK", HALT);
}
// Request a page from an HTTP server.
boolean requestPage(String host, String page, int port)
{
// Create raw HTTP request for web page.
String http_req = "GET " + page + " HTTP/1.1\r\nHost: " + host + ":" + port + "\r\n\r\n";
// Ready the module to receive raw data.
String cmd = "AT+CIPSEND=0,";
cmd = cmd + http_req.length(); // Tell the ESP8266 how long the coming HTTP request is.
if (!echoCommand(cmd, ">", CONTINUE))
{
echoCommand("AT+CIPCLOSE", "", CONTINUE);
errorHalt("Connection timeout");
}
// Send the raw HTTP request.
return echoCommand(http_req, "OK", CONTINUE);
}
HardwareSerial esp8266(2); // Find the ZPUino serial port connected to the ESP8266.
void setup()
{
Serial.begin(115200); // Initialize serial port to the PC.
Serial1 = esp8266; // Rename the ESP8266 serial port to something more standard.
// Initialize the serial port to the ESP8266, but also assign the RX & TX lines
// to specific pins of the ZPUino FPGA. Obviously, this part is not needed when
// using a standard Arduino.
Serial1.begin(115200, TX(3), RX(17));
// Wait for a keypress from the PC before running the demo.
while(!Serial.available())
;
Serial.read();
Serial.println("\n\n\n\r----------- ESP8266 Demo -----------\n\n");
echoCommand("AT+RST", "ai-thinker.com]", HALT); // Reset the module.
echoCommand("AT+GMR", "OK", CONTINUE); // Show module's firmware ID.
echoCommand("AT+CWMODE=1", "", CONTINUE); // Set module into station mode.
echoCommand("AT+CIPMUX=1", "OK", CONTINUE); // Allow multiple connections. Necessary for TCP link.
delay(2000); // Let things settle down for a bit...
echoCommand("AT+CWLAP", "OK", HALT); // Scan for available access points.
// Connect to the Wifi.
for(int i=1; i<=CONNECTION_TRIES; i++)
{
if(connectWiFi(SSID, PASS))
break;
if(i == CONNECTION_TRIES)
errorHalt("Connection failed");
}
delay(4000); // Let the link stabilize.
echoCommand("AT+CIFSR", "", HALT); // Show the IP address assigned by the access point.
}
void loop()
{
establishTcpLink(DEST_IP, DEST_PORT);
delay(2000); // Once again, let the link stabilize.
// Show the connection status.
echoCommand("AT+CIPSTATUS", "OK", HALT);
// Request a page from an HTTP server.
requestPage(DEST_HOST, DEST_PAGE, DEST_PORT);
// Loop forever echoing data received over the Wifi from the HTTP server.
while(true)
echoPacket();
errorHalt("ONCE ONLY");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment