-->
Page 1 of 1

GPS UDP Broadcaster

PostPosted: Wed Sep 16, 2015 8:01 am
by mrburnette
This is a work in progress; which is to say it works but is not stable... the AP will eventually "hang" and it is not likely a stack issue as the console continuously shows free memory greater than 20K... 26784 generally but occasionally changes are displayed ... every 10K loop.

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:
Code: Select all/*
   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:
Code: Select all// 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

Re: GPS UDP Broadcaster

PostPosted: Tue Nov 10, 2015 10:01 am
by mrburnette
Youtube vid:

https://www.youtube.com/watch?v=CiUsixR9Gw4

The GPS and ESP8266 AP are in the attic. The video is of an '8266 on breadboard in the basement. Acquisition time is very good on the 12E. The 5V to 3.3V DC-DC module provides a good, stable voltage.

Ray

Re: GPS UDP Broadcaster

PostPosted: Tue Nov 10, 2015 2:32 pm
by danbicks
Ray, nice work, glad my Oled example came in handy.

Well done for leaving credits :)

Regards

Dans