Note: the sketch originally had an HTTP webserver, too. I removed this code looking for the instability - the webserver was not at fault, but I have not replaced the code... references remain.
The code requires Streaming.h from
http://arduiniana.org/libraries/streaming/
and
the Utility library from this source:
https://github.com/internetofhomethings/ESP8266-WeatherSensor-Webserver/blob/master/UtilityFunctions.h
I am using a Chinese U-blox 6 GPS running at 1PPS with the serial at 9600 BAUD. IF your GPS processes faster than 1PPS, you should reprogram it to 1PPS - see your user manual.
Essentially, I set up an AP and a UDP broadcast to 255.255.255.255 which is reasonably easy using this code:
/*
GPS Portal, part of Tardis Time Server by: M. Ray Burnette 20150915
Create a private 10. network and capture all DNS requests to the Time Portal
Respond to UDP and DHCP and DNS
Compiled under Arduino 1.6.6 Hourly build 2015/09/04 04:42
Sketch uses 340,080 bytes (78%) of program storage space. Maximum is 434,160 bytes.
Global variables use 50,796 bytes (62%) of dynamic memory, leaving 31,124 bytes for local variables. Maximum is 81,920 bytes.
*/
#define LEDpin 2 // ESP82660-1 8-pin module LED is on GPIO-02
#include <Streaming.h> // \Documents\Arduino\libraries\Streaming (legacy)
#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
#include <DNSServer.h>
#include "./Utility.h" // See Notes tab for credits
const byte DNS_PORT = 53; // Listen DNS requests on port 53
int ack_Count = 0;
int counter;
uint8_t hour, minute, seconds; // hour, minure, seconds,
uint8_t day, month, year; // year, month, day;
unsigned int localPort = 8888; // any unused port on LAN
IPAddress apIP(10, 10, 10, 1); // Private network address: local & gateway
IPAddress broadcastIP(255, 255, 255, 255);
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; // buffer to hold incoming packet,
char ReplyBuffer[] = "????????????"; // a 12 character string to send back
DNSServer dnsServer; // Create the DNS object
WiFiUDP UDP; // UDP protocol on STA interface, localPort
extern "C" {
#include "user_interface.h" // used for diagnostic ESP.getFreeHeap()
}
void setup()
{
Serial.begin(9600); // Initialise Serial connection
Serial << (F("2015 Ray Burnette")) << endl;
Serial << (F("Tardis Time Portal Version 0.20150915")) << endl;
Serial << (F("Visit my project web page on http://www.hackster.io/rayburne")) << endl << endl;
WiFi.mode(WIFI_AP_STA); // AP + STA
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); // subnet FF FF FF 00
WiFi.softAP("TardisTime");
dnsServer.start(DNS_PORT, "*", apIP); // "*" creates a captive portal
while (! UDP.begin(localPort) ) { // UDP protocol connected to localPort which is a variable
Serial << "+" ;
yield(); // Play nicely with RTOS (alias = delay(0))
} // This will loop forever if UDP fails
Serial << endl;
Serial << (F("Setting pin#2 to Output mode")) << endl;
pinMode(2, OUTPUT); // initialise pin mode
}
void loop()
{
dnsServer.processNextRequest(); // TCP Address handler when requested
yield(); // yield for RTOS
// Listener(); // UPD (can you hear me now?)
// yield();
if (Serial.available() > 0) { // anything in the serial hw buffer?
char c = Serial.read(); // if so, fetch the next character from FIFO
GPSstuff(c);
}
yield();
++counter;
if (counter > 9999) { // for diagnostics, no other purpose
long int RAM = ESP.getFreeHeap();
Serial << "Free= " << RAM << endl;
counter = 0;
digitalWrite(LEDpin, !(digitalRead(LEDpin))); // blink LED (Warning: using ESP8266-01 module)
yield();
}
} // loop repeats forever unless stack crashes or uC hangs
void GPSstuff(char c) { // GPSbuffer[] is global
static int i, j; // persistent within function scope
static char q;
static bool flag = false;
static char GPSbuffer[120]; // GPS serial line input buffer
q = c;
if ( q == 0x24 ) // '$'
{
i = 0; // brute force sync on '$' to GPSbuffer[0]
// Serial << "Found $" << endl;
}
if ( i < 120) GPSbuffer[i++] = q;
// Serial << "Index=" << (i -1) << "Input=" << q << endl;
//if (i = 120) i = 119; // array limit safety
if (q == 0x0d) {
flag = true; // is the character a CR for eol
i = 0;
}
if (flag) { // test for end of line and if the right GPSbuffer
flag = false; // reset for next time
UDP.beginPacketMulticast(broadcastIP, localPort, apIP);
// Serial << "We are in the flag routine..." << GPSbuffer[3] << GPSbuffer[4] << GPSbuffer[5] << endl;
// Serial << "Analyzing " << GPSbuffer[3] << GPSbuffer[4] << GPSbuffer[5] << endl;
if ( (GPSbuffer[3] == 0x52) && (GPSbuffer[4] == 0x4d) && (GPSbuffer[5] == 0x43)) // 'R' && 'M' && 'C'
{
for (j = 0; j < 120 ; j++) {
UDP.write(GPSbuffer[j]);
}
UDP.write("\r\n"); // terminate the line
UDP.endPacket(); // clear UDP buffer
}
}
}
A remote PC is now being used as the GPRMC receiver but eventually this will be replaced with another ESP8266 (one or more) that will parse the time/date fields and format them for a nice clock display.
The test code for the PC using Processing 3 alpha:
// Processing UDP example to send and receive binary data
// https://thearduinoandme.wordpress.com/t utorials/esp8266-send-receive-binary-data/
// Badly hacked by Ray B. to display the UDP broadcast from ESP8266
import hypermedia.net.*; // http://ubaa.net/shared/processing/udp/udp_class_udp.htm
String ip = "10.10.10.1"; // the remote IP address of ESP8266
int port = 8888; // the destination port - any unused port
long previousMillis = 0;
long interval = 500;
UDP udp;
void setup() {
udp = new UDP(this, 8888);
udp.listen( true );
}
void draw() {
if (previousMillis < millis() - interval) {
previousMillis = previousMillis + interval;
byte[] message = new byte[2];
message[0] = 0; message[1] = 0;
udp.send(message, ip, port);
}
}
void keyPressed() {
if (key == '-')
{
byte[] message = new byte[2];
message[0] = 0; message[1] = 0;
udp.send(message, ip, port);
}
}
void keyReleased() {
if (key != '-') {
byte[] message = new byte[2];
message[0] = 0; message[1] = 0;
udp.send(message, ip, port);
}
}
void receive( byte[] data ) { // <– default handler
for (int i=0; i < data.length; i++)//void receive( byte[] data, String ip, int port ) { // <– extended handler
print(char(data[i]));
println();
}
The above code is from a Processing example - I am not the author but I surely did hack it.
To test: set up the AP with the GPS feeding URXD. I used the -01 model and put a led on GPIO2 with GPIO0 remaining used for the bootloader only. UTXD is going to a serial-USB to the PC for monitoring with the terminal emulator set at 9600 BAUD.
Connect to the AP from the remote PC by selecting the AP name: TardisTime
Load the Processing Script
Compile/Run the script
That should be it. Eventually, this sketch will be added to my projects blog on:
http://www.hackster.io/rayburne
https://www.hackster.io/rayburne/tardis-time-esp8266-ap-webserver-gps
Ray