GPS-coords displayed directly on OLED-screen

I have created a small project with GPS and OLED. I started it in preparation for the Electron, because I anticipated that some examinations beforehand would refresh my knowledge.
I did not think about publishing it until I realized that a lot of discussion went around the GPS-signals and how to obtain them and wether they are right or not. Point is simple that we usually can not go outdoors and code in all-weather-conditions. The best solution I have seen so far is an Electron on a dashboard.
However, the solution is quite simple: Use a small display and print all desired informations on it. That’s what’s the project is about.

The photo shows the variant with the SparkFun Photon RedBoard.

This is the code, based on TinyGPS:

    // This #include statement was automatically added by the Particle IDE.
    #include "Adafruit_SSD1306/Adafruit_SSD1306.h"
    // This #include statement was automatically added by the Spark IDE.
    #include "TinyGPS/TinyGPS.h"
    
    #include "math.h"
    
    
    
    TinyGPS gps;
    
    #define OLED_RESET D4
    #define OLED_POWER A0
    // This is part of a hardware hack
    // The sparkfun board has no 5V socket, instead it has USB-5V.
    // It means, there is only 5V, if USB is connected.
    // The other option would be VIN.
    // The docs claim, that the voltage is the same as on the plug, e.g. a 9V-battery gives 9 Volt here.
    // Nothing could be more dangerous, that is quite unfair.
    // The solution is, that a digital is set to HIGH and delivers the power.
    
    Adafruit_SSD1306 display(OLED_RESET);
    
    
    bool hasFix = false;
    
    char displayString[26];
    char latLonString[26];
    
    char compassDir []= "NSEW";// for all directions
    bool smallTextStyle = true;
    
    
    void setup(){
        Serial1.begin(9600);
        pinMode(OLED_POWER, OUTPUT);
        digitalWrite(OLED_POWER, HIGH);
        delay(100);
        
        
        //   Serial.begin(9600);
        
        display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
        
        // Show image buffer on the display hardware.
        // Since the buffer is intialized with an Adafruit splashscreen
        // internally, this will display the splashscreen.
        display.display();
        delay(2000);
        
        // Clear the buffer.
        display.clearDisplay();
        display.setTextColor(WHITE);
        display.setCursor(0,0);
        display.setTextSize(2);
        display.println("-/-");
        display.display();
        Particle.function("gps", gpsPublish);
        
        
        
        //   Serial.println("This will test the functionality of Serial");
        
    }

void loop(){
    bool hasData = false;
    bool isValidData = false;

    display.clearDisplay();
    display.setCursor(0,0);
    if(smallTextStyle)
        display.setTextSize(1);
    else
        display.setTextSize(2);
    
    
    
    for (unsigned long start = millis(); millis() - start < 1000;){
        // Check GPS data is available
        while (Serial1.available()){
            
            hasData = true;
            char c = Serial1.read();
            
            
            // parse GPS data
            if (gps.encode(c))
            {
                isValidData = true;
            }
        }
    }
    
    // If we have a valid GPS location then publish it
    if (isValidData){
        
        float f_lat;
        float f_lon;
        unsigned long age;
        unsigned int secs;
        
        gps.f_get_position(&f_lat, &f_lon, &age);
        
        if(f_lat == TinyGPS::GPS_INVALID_F_ANGLE  ||
           f_lon == TinyGPS::GPS_INVALID_F_ANGLE)
        {
            hasFix = false;
            sprintf(latLonString, "0.0, 0.0");
        }
        
        else
        {
            hasFix = true;
            sprintf(latLonString, "%.6f,%.6f", f_lat, f_lon);
            
            for(int i=0; i< 2; i++)// translate the coords from Decimal Degrees (D.D°) to Decimal Minutes (D° M.M') 
            {
                float coord = (0==i) ? f_lat : f_lon;
                int j = (coord < 0.0)? 1 : 0;
                j += i*2;
                char direction = *(compassDir + j);
                
                float degrees = floor(coord);
                float f_minutes = (coord - degrees) * 60;
                
                unsigned int deg = (unsigned int) degrees;
                unsigned int i_minutes = (unsigned int) floor(f_minutes);
                secs = (unsigned int)round((f_minutes - (float)i_minutes)*1000);
                char separator =  smallTextStyle ? ' ' : '\n';
                
                sprintf(displayString, "%c%c %02d %02d.%03d",direction, separator, deg, i_minutes, secs);
                
                display.println(displayString);
            }
            
            if(smallTextStyle)// display time and date, satellites' count and altitude
            {
                int year;
                byte month, day, hour, minute, second, hundredths;
                //            float falt = gps.f_altitude();
                
                unsigned long value;
                char emptyStr[] = "";
                int satellites = gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites();
                strcpy(displayString, emptyStr);
                for(int i=0; i< satellites; i++)
                    strcat(displayString, "*");
                display.println(emptyStr);
                display.println(displayString);
                display.println(emptyStr);
                gps.crack_datetime(&year, &month, &day,
                                   &hour, &minute, &second, &hundredths, &value);
                sprintf(displayString, "%02d:%02d:%02d  %02d.%02d.%04d",hour, minute, second, day, month, year);
                
                display.println(displayString);
                value = gps.speed();//100ths of a knot
                //            float f_value = value * 182.5;// * 100 *1.825 knots
                //            sprintf(displayString, "%5.1f km",f_value);
                //            Serial.println(value);
                //            Serial.println(f_value);
                //            display.println(emptyStr);
                //            display.println(displayString);
                
                value = (gps.altitude())/100;//cm
                //            f_value = value * 0.01;// * 100 *1.825 knots
                sprintf(displayString, "%ld m", value);
                display.println(displayString);
                //Serial.println(value);
            }
            
            Particle.publish("gps", latLonString);
        }
        
        if(false == hasFix)
        {
            unsigned long chars;
            unsigned short sentences, failed;
            
            gps.stats(&chars, &sentences, &failed);

            if (chars == 0)
            {
                sprintf(displayString, "chars: %02d\n sentences:%d\n   failed: %d",chars, sentences, failed);
                display.println(displayString);
            }
            else
            {
                display.println(latLonString);
                
                display.println("...searching...");
                // Not a vlid GPS location, just pass 0.0,0.0
                // This is not correct because 0.0,0.0 is a valid GPS location, we have to pass a invalid GPS location
                // and check it at the client side
            }
        }
    }
    
    if(false == hasData)
    {
        display.println("no data");
    }
    
    else if (false == isValidData)
    {
        display.println("\n No valid GPS data!\n\n   ...searching...");
    }
    

    display.display();
    
}

int gpsPublish(String command){
    if(hasFix){
        Particle.publish("G", latLonString, 60, PRIVATE);
        
        // uncomment next line if you want a manual publish to reset delay counter
        // lastPublish = millis();
        return 1;
    }
    else { return 0; }
}
3 Likes