Wifi-GPS-Topspeed-Meter

Arduino on Lilygo OLED Lora ESP32 (board TTGO-Lora32-OLED V1″)

#define USE_OLED

#ifdef USE_OLED
//Libraries for OLED Display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#endif

#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiAP.h>

const char *ssid = "GPSWIFI";
const char *password = "12345678";

WiFiServer server(80);

const unsigned char ubxRate1Hz[]  = 
  { 0x06,0x08,0x06,0x00,0xE8,0x03,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate5Hz[]  =
  { 0x06,0x08,0x06,0x00,200,0x00,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate10Hz[]  =
  { 0x06,0x08,0x06,0x00,100,0x00,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate16Hz[]  =
  { 0x06,0x08,0x06,0x00,50,0x00,0x01,0x00,0x01,0x00 };

// Disable specific NMEA sentences
const unsigned char ubxDisableGGA[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableGLL[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x01,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableGSA[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x02,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableGSV[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x03,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableRMC[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x04,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableVTG[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x05,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableZDA[]  =
  { 0x06,0x01,0x08,0x00,0xF0,0x08,0x00,0x00,0x00,0x00,0x00,0x01 };


#define Battadc 36
#define ADC_FACTOR (0.000635*2.0*1.362)
#define BATT_LOW 3.5

#define SDA 21
#define SCL 22

#ifdef USE_OLED
//OLED pins
#define OLED_SDA 4
#define OLED_SCL 15 
#define OLED_RST 16
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);
#endif

bool enable_dbg;
bool sig_valid, sig_rxok;
float sig_speed, saved_spd;
int sig_sats;
#define NUM_V_ENTRIES 5
float maxspeed[NUM_V_ENTRIES];
int vbatt;

// Cut out the wanted substring from a comma-separated string
static String extract_val(char *buf, int len, int cpos)
{
  String str="";
  int i,cc=0,cs=0,ce=255;
  for (i=0;i<len;i++) {
    if (buf[i]==',') {
      cc++; // count commas
      if(cc==cpos) cs=i+1;
      if(cc==cpos+1) {ce=i; break;}
    }
    else if (buf[i]=='*' || buf[i]=='\r')
      ce=i;
  }
  if (cs == 0) // no comma seen - no result
    return str;
  int s = min(ce-cs, 255);
  for (i=0; i<s; i++) // build string, could be nicer...
    str+=(char)buf[cs+i];
//  memcpy(tgt, &buf[cs], s);
  return str;
}

void parse_gps(char c) {
  static char buf[127];
  static int pos=0;
  if (c=='\n') {
    buf[pos]=0;
    if (buf[2]=='V' && buf[3]=='T' && buf[4]=='G') {
      sig_rxok = true;
      String s = extract_val(buf, pos, 7);
      if (s.length() > 0)
        sig_valid = true;
      Serial.println(s);
      sig_speed = s.toFloat();
      saved_spd = sig_speed;
    }
    else if (buf[2]=='G' && buf[3]=='G' && buf[4]=='A') {
#ifdef USE_OLED
      display.print(buf);
#endif
      String s = extract_val(buf, pos, 7);
      Serial.println(s);
      sig_sats = s.toInt();
    }
  }
  else if (c=='$') pos=0;
  else if (pos < sizeof(buf))
    buf[pos++] = c;
}

//Warteschleife, die ankommende Daten vom GPS Modul verarbeitet und den Status des Tasters prüft
static void smartdelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    while (Serial2.available()) {
      char c=Serial2.read();
      parse_gps(c);
      if (enable_dbg) Serial.print(c);
      //display.print(c);
    }
    //display.display();
  } while (millis() - start < ms);
}

static void sendUBX( const unsigned char *progmemBytes, size_t len )
{
  Serial2.write( 0xB5 ); // SYNC1
  Serial2.write( 0x62 ); // SYNC2

  uint8_t a = 0, b = 0;
  while (len-- > 0) {
    uint8_t c = ( *progmemBytes++ );
    a += c;
    b += a;
    Serial2.write( c );
  }

  Serial2.write( a ); // CHECKSUM A
  Serial2.write( b ); // CHECKSUM B
  delay(100);
}

static void updateRate()
{
  sendUBX(ubxRate5Hz, 10);
}

void setup() { 
  pinMode(0, INPUT_PULLUP); // button
  pinMode(SCL, INPUT_PULLUP); // I2C of GPS compass
  pinMode(SDA, INPUT_PULLUP);

//  analogSetAttenuation(ADC_0db); // control sensitivity; ADC_11db, ADC_6db, ADC_2_5db, ADC_0db
//  pinMode(Battadc, INPUT);
//  adcAttachPin(Battadc);

  Serial.begin(115200); // debug
  Serial2.begin(9600,SERIAL_8N1,12,13); // GPS
  
#ifdef USE_OLED
  //reset OLED display via software
  pinMode(OLED_RST, OUTPUT);
  digitalWrite(OLED_RST, LOW);
  delay(20);
  digitalWrite(OLED_RST, HIGH);

  //initialize OLED
  Wire.begin(OLED_SDA, OLED_SCL);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { // Address 0x3C for 128x32
    //Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
#endif

  // setup WIFI server
  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP(); // usually 192.168.4.1
  server.begin();

#ifdef USE_OLED
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Simon's WIFI GPS");
  display.println("IP address:");
  display.println(myIP);
  display.display();
#endif

  delay(2000);
  sendUBX(ubxDisableGLL, 12);
  sendUBX(ubxDisableGSA, 12);
  sendUBX(ubxDisableGSV, 12);
  sendUBX(ubxDisableRMC, 12);
  sendUBX(ubxDisableZDA, 12);
  Serial2.print("$PUBX,41,1,0007,0003,19200,0*25\r\n");
  Serial2.flush();
  delay(100);
  Serial2.end();
  Serial2.begin(19200,SERIAL_8N1,12,13);
  delay(1000);
  updateRate();
}

void wifi() {
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    char i;
    Serial.println("New Client.");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
//        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            // the content of the HTTP response follows the header:
            char tmp[32];
            client.print("<html><head><meta http-equiv=\"refresh\" content=\"10; URL=/\" /></head>");
            client.print("<body style=\"background-color:black;\"><h1 style=\"color:white;font-size:80px\">Simon's WIFI GPS</h1>");
            client.println("<p style=\"color:white;font-size:60px\"><b>");
            sprintf(tmp, "Max = %4.1f km/h", maxspeed[0]);
            client.print(tmp);
            client.println("</p><p style=\"color:white;font-size:30px\">");
            for (i=1;i<NUM_V_ENTRIES;i++) {
              sprintf(tmp, "%4.1f km/h", maxspeed[i]);
              client.print(tmp);
              client.println("<br>");
            }
            sprintf(tmp, "<br>Batt = %2.3f V", (float)vbatt*ADC_FACTOR);
            client.print(tmp);
            client.println("<br>");

            sprintf(tmp, "<br>Signal rx ok = %d", sig_rxok);
            client.print(tmp);
            client.println("<br>");

            sprintf(tmp, "<br># of satellites = %d", sig_sats);
            client.print(tmp);
            client.println("<br>");

            client.print("<br><br><a href=\"/R\">RESET</a> Vmax.<br></p></body></html>");

            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
          } else {    // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /R")) {
          for (i=0; i<NUM_V_ENTRIES; i++)
            maxspeed[i] = 0.0;
        }
      }
    }
    // close the connection:
    client.stop();
//    Serial.println("Client Disconnected.");
  }
}

void loop() {
  int i;
  bool spdwritten = false;
  char tmp[32];
  float spd;
  
  smartdelay(0);
#ifdef USE_OLED
  display.clearDisplay(); // drawString(x,y,text);? or ACROBOTIC_SSD1306 with setTextXY/putString
  display.setCursor(0, 0);
#endif
  if (sig_valid) {
    spd = sig_speed;
    sig_speed = 0.0;
    // show maximum speed, with 5 places to see glitches
#ifdef USE_OLED
    display.println("Geschwindigkeit (max)");
#endif
    for (i=0; i<NUM_V_ENTRIES; i++) {
      if (spd > maxspeed[i] && !spdwritten) {
        maxspeed[i] = spd;
        spdwritten = true;
        break;
      }
    }
#ifdef USE_OLED
    for (i=0; i<NUM_V_ENTRIES; i++) {
      if (i==0)
        display.setTextSize(2);
      sprintf(tmp, "%4.1f km/h", maxspeed[i]);
      display.println(tmp);
      if (i==0)
        display.setTextSize(1);
    }
    // show current speed
    sprintf(tmp,"S%4.1f  Sats %3d", saved_spd, sig_sats);
    display.print(tmp);
  } else {
    display.println("No GPS fix.");
    if (sig_rxok)
      display.println("GPS RX ok");
    sprintf(tmp,"         Sats %3d", sig_sats);
    display.print(tmp);
#endif
  }
  vbatt = analogRead(Battadc);
#ifdef USE_OLED
  if ((float)vbatt*ADC_FACTOR < BATT_LOW) {
    display.setCursor(108, 32);
    display.print("LOW");
  }
  display.display();
#endif
  if (digitalRead(0)==0) { // clear
    for (i=0;i<NUM_V_ENTRIES; i++)
      maxspeed[i] = 0.0;
#ifdef USE_OLED
    display.clearDisplay();
#endif
  }
  wifi();
}