GPS - NMEA decoder $GPGSV

Hello
Before reinventing the wheel, do you know a sketch using MNEA $GPGSV to have position and signal of satellites ?
Thank you.

Satellite information

The GSV message string identifies the number of SVs in view, the PRN numbers, elevations, azimuths, and SNR values. An example of the GSV message string is:

$GPGSV,3,1,11,06,13,085,20,10,10,270,10,12,80,291,20,14,11,321,2272
$GPGSV,3,2,11,15,25,180,25,17,15,038,37,18,03,246,,19,32,051,38
74
$GPGSV,3,3,11,24,75,101,33,29,02,196,21,32,28,311,28*4B

GSV message fields
Field Meaning
0 Message ID $GPGSV
1 Total number of messages of this type in this cycle
2 Message number
3 Total number of SVs visible
4 SV PRN number
5 Elevation, in degrees, 90° maximum
6 Azimuth, degrees from True North, 000° through 359°
7 SNR, 00 through 99 dB (null when not tracking)
8–11 Information about second SV, same format as fields 4 through 7
12–15 Information about third SV, same format as fields 4 through 7
16–19 Information about fourth SV, same format as fields 4 through 7
20 The checksum data, always begins with *

TinyGPG and TinyGPS++ do not use this sentence and I am not good enough to make an implementation of this library ...

NeoGPS.

You have to change the default configuration file NMEAGPS_cfg.h to (1) enable parsing the GSV sentence:

#define NMEAGPS_PARSE_GGA
//#define NMEAGPS_PARSE_GLL
//#define NMEAGPS_PARSE_GSA
#define NMEAGPS_PARSE_GSV    // <-- uncomment this line (line 19)
//#define NMEAGPS_PARSE_GST
#define NMEAGPS_PARSE_RMC
//#define NMEAGPS_PARSE_VTG
//#define NMEAGPS_PARSE_ZDA

... (described here), and (2) enable saving the satellite "views" in the satellites array:

//------------------------------------------------------
// Enable/disable tracking the current satellite array and,
// optionally, all the info for each satellite.
//

#define NMEAGPS_PARSE_SATELLITES      // <-- uncomment line 192
#define NMEAGPS_PARSE_SATELLITE_INFO  // <-- uncomment this if you want elev/azim/SNR/tracked

#ifdef NMEAGPS_PARSE_SATELLITES
  #define NMEAGPS_MAX_SATELLITES (20)  // <-- change this array size if you want

Described here.

The satellite array is in the NMEAGPS object:

    Serial.print( gps.satellites[ i ].elevation )

Data structure described here, C++ definition here.

Your sketch should be structured something like this:

#include <NMEAGPS.h>

NMEAGPS  gps; // This parses the GPS characters
gps_fix  fix; // This holds on to the latest values

//-----------------
//  Prerequisites:
//     1) NMEA.ino works with your device (correct TX/RX pins and baud rate)
//     2) GPS_FIX_SATELLITES is enabled in GPSfix_cfg.h
//     3) NMEAGPS_PARSE_SATELLITES and NMEAGPS_PARSE_SATELLITE_INFO are
//              enabled in NMEAGPS_cfg.h
//     4) The GSV sentence has been enabled in NMEAGPS_cfg.h.
//     5) Your device emits the GSV sentence (use NMEAorder.ino to confirm).
//     6) LAST_SENTENCE_IN_INTERVAL has been set to GSV (or any other enabled sentence)
//              in NMEAGPS_cfg.h (use NMEAorder.ino).
//
//  'Serial' is for debug output to the Serial Monitor window.
//

//-----------------
//   Choose a serial port for the GPS device:
//
//   BEST: For a Mega, Leonardo or Due, use the extra hardware serial port
#define gpsPort Serial1

//   2nd BEST:  For other Arduinos, use AltSoftSerial on the required pins
//                 (8&9 for an UNO)
// #include <AltSoftSerial.h>
// AltSoftSerial gpsPort;  // pin 8 to GPS TX, pin 9 to GPS RX

//   3rd BEST:  If you can't use those specific pins (are you sure?),
//                 use NeoSWSerial on any two pins @ 9600, 19200 or 38400
// #include <NeoSWSerial.h>
// NeoSWSerial gpsPort( 2, 3 ); // pin 2 to GPS TX, pin 3 to GPS RX

//   WORST:  SoftwareSerial is NOT RECOMMENDED

//-----------------

void setup()
{
  Serial.begin(9600);
  while (!Serial)
    ;
  Serial.print( F("NeoGPS GSV example started\n") );

  gpsPort.begin(9600);

} // setup

//-----------------

void loop()
{
  while (gps.available( gpsPort )) {
    fix = gps.read();

    displaySatellitesInView();
  }

} // loop

//-----------------

void displaySatellitesInView()
{
  Serial.print( gps.sat_count );
  Serial.print( ',' );

  for (uint8_t i=0; i < gps.sat_count; i++) {
    Serial.print( gps.satellites[i].id );
    Serial.print( ' ' );
    Serial.print( gps.satellites[i].elevation );
    Serial.print( '/' );
    Serial.print( gps.satellites[i].azimuth );
    Serial.print( '@' );
    if (gps.satellites[i].tracked)
      Serial.print( gps.satellites[i].snr );
    else
      Serial.print( '-' );
    Serial.print( F(", ") );
  }

  Serial.println();

} // displaySatellitesInView

This will be added as an example in the next release of NeoGPS.

Cheers,
/dev

Thank you very much for your answer ... I will try this librairy.

I read than the SoftwareSerial library provided with the IDE is inadequate.
I use NewSoftSerial (on any two pins @ any baud) by Mikal Hart.

You suggest AltSoftSerial (only pins 8&9 for an UNO) or NeoSWSerial (on any two pins @ 9600, 19200 or 38400).

In my case (UNO R3), I need 2 serial port (waiting MEGA), what is best/faster NewSoftSerial VS NeoSWSerial ?

neutrinos:
I read that the SoftwareSerial library provided with the IDE is inadequate.
I use NewSoftSerial (on any two pins @ any baud) by Mikal Hart.

You read wrong, or you read something very old. "NewSoftSerial" was incorporated in the IDE as "SoftwareSerial" a long time ago.

what is best/faster

Read this for all the choices.

I have modified your function for (in my mind) best display.

After I add a condition && gps.sat_count != nbsat to group by changing number of sat.

Now I want complet it with time and date when number of sat change and I have problem to do it.
Whith tinyGPS I undestand, but your librairy is too technical for me.
Please explain me ...

void TableSatellitesInView()
{
  int nbcol = 7;
  char text[nbcol * 15 + 6];
  static int nbsat = 0;
  if(gps.sat_count && gps.sat_count != nbsat)
  { int i = 0;
    nbsat = gps.sat_count;
    Serial.println();

  if (fix.valid.time && fix.valid.date) 
{    Serial.print("time and date are : ");
  //  Serial.print( ); // time and date
    Serial.println();
}
     Serial.print("nb |");
      for ( i=0; i < nbcol; i++) 
      {  Serial.print(" id el  az tr |");
      }
      Serial.println();
      Serial.print("---|");
      for ( i=0; i < nbcol; i++) 
      {  Serial.print("--------------|");
      }
     Serial.println();
      sprintf(text,"%2d |",gps.sat_count);
      Serial.print(text);
      for ( i=0; i < gps.sat_count; i++) 
      { if(i % nbcol+1 == nbcol)
        { Serial.println();
          Serial.print("   |");
        }
         sprintf(text," %2d %2d %3d ",gps.satellites[i].id,gps.satellites[i].elevation,gps.satellites[i].azimuth);
         Serial.print(text);
         if (gps.satellites[i].tracked)
         {  sprintf(text,"%2d",gps.satellites[i].snr);
            Serial.print(text);
         }
         else
            Serial.print( "--" );
         Serial.print( F(" |") );
      }
      for ( i= i % nbcol+1 ; i < nbcol; i++) 
      {  Serial.print("--------------|");
}
      
 
      Serial.println();
      Serial.print("====");
      for (uint8_t i=0; i < nbcol; i++) 
      {  Serial.print("===============");
      }
     }

  
} // TableSatellitesInView

Now I want complete it with time and date when number of sat change

Ok, here are some techniques for you, taken from the Tabular.ino example:

#include <NMEAGPS.h>

NMEAGPS  gps; // This parses the GPS characters
gps_fix  fix; // This holds on to the latest values

//-----------------
//   Choose a serial port for the GPS device:
//
//   BEST: For a Mega, Leonardo or Due, use the extra hardware serial port
#define gpsPort Serial1

//   2nd BEST:  For other Arduinos, use AltSoftSerial on the required pins
//                 (8&9 for an UNO)
// #include <AltSoftSerial.h>
// AltSoftSerial gpsPort;  // pin 8 to GPS TX, pin 9 to GPS RX

//   3rd BEST:  If you can't use those specific pins (are you sure?),
//                 use NeoSWSerial on any two pins @ 9600, 19200 or 38400
// #include <NeoSWSerial.h>
// NeoSWSerial gpsPort( 2, 3 ); // pin 2 to GPS TX, pin 3 to GPS RX

//   WORST:  SoftwareSerial is NOT RECOMMENDED

//-----------------

void setup()
{
  Serial.begin(9600);
  while (!Serial)
    ;
  Serial.print( F("NeoGPS GSV example started\n") );

  gpsPort.begin(9600);

} // setup

//-----------------

static int8_t                    nbsat = 0;
static NMEAGPS::satellite_view_t lastSatellites[ NMEAGPS_MAX_SATELLITES ];

void loop()
{
  bool different = false;

  while (gps.available( gpsPort )) {
    fix = gps.read();

    // Compare satellite count
    different = (nbsat != gps.sat_count);

    if (!different) {

      // Same number of satellites, compare IDs
      for (uint8_t i=0; i < nbsat; i++) {
        bool found = false;

        for (uint8_t j=0; j < nbsat; j++) {
          // Search the old array for each new ID
          if (lastSatellites[i].id == gps.satellites[j].id) {
            found = true;

            // You could *compare* the elev/az/SNR/tracked pieces
            if (lastSatellites[i].elevation != gps.satellites[j].elevation)
              different = true;

            // You could *update* the elev/az/SNR/tracked pieces
            // lastSatellites[i].elevation = gps.satellites[j].elevation;
            // lastSatellites[i].azimuth   = gps.satellites[j].azimuth;
            // lastSatellites[i].snr       = gps.satellites[j].snr;
            // lastSatellites[i].tracked   = gps.satellites[j].tracked;
            break;
          }
        }

        if (!found) {
          different = true;
          break;
        }
      }
    }

    if (different) {
      // Save the new satellites array
      nbsat = gps.sat_count;
      for (uint8_t i=0; i < nbsat; i++) {
        lastSatellites[i] = gps.satellites[i];
      }
    }
  }

  if (different)
    TableSatellitesInView();

} // loop

//-----------------

#define CF(x) ((const __FlashStringHelper *) x) // a helper macro for the headers

static const char   NB_HEADER[] PROGMEM  = "nb ";
static const int8_t NBCOL_WIDTH          = sizeof(NB_HEADER)-1;

static const char   SAT_HEADER[] PROGMEM = " id el  az tr ";
static const int8_t SAT_COL_WIDTH        = sizeof(SAT_HEADER)-1;

static const int8_t NBCOL = 7;

void TableSatellitesInView()
{
  nbsat = gps.sat_count;

  int i = 0;

  if (fix.valid.time && fix.valid.date) {
    Serial.print( F("time and date are : ") );
    Serial << fix.dateTime; // this "streaming" operator outputs date and time
    Serial.println();
  }

  Serial.print( CF(NB_HEADER) );
  Serial.print( '|' );
  for ( i=0; i < NBCOL; i++) {
    Serial.print( CF(SAT_HEADER) );
    Serial.print( '|' );
  }
  Serial.println();

  repeat( '-', NBCOL_WIDTH );
  Serial.print( '|' );
  for ( i=0; i < NBCOL; i++) {
    repeat( '-', SAT_COL_WIDTH );
    Serial.print( '|' );
  }
  Serial.println();

  print( gps.sat_count, NBCOL_WIDTH-1 );
  Serial.print( F(" |") );

  for ( i=0; i < gps.sat_count; i++) {
    print( gps.satellites[i].id       , 3 );
    print( gps.satellites[i].elevation, 3 );
    print( gps.satellites[i].azimuth  , 4 );
    if (gps.satellites[i].tracked)
      print( gps.satellites[i].snr, 3 );
    else
      Serial.print( F(" - ") );
    Serial.print( F(" |") );

    if ((i % NBCOL) == (NBCOL-1)) {
      Serial.println();
      repeat( ' ', NBCOL_WIDTH );
      Serial.print( '|' );
    }
  }

  i = (i % NBCOL);
  while (i++ < NBCOL) {
    repeat( ' ', SAT_COL_WIDTH );
    Serial.print( '|' );
  }
  Serial.println();

  repeat( '=', (NBCOL_WIDTH+1) + NBCOL * (SAT_COL_WIDTH+1) );
  Serial.println();

} // TableSatellitesInView

//-----------------
//  Print utilities

static void repeat( char c, int8_t len )
{
  for (int8_t i=0; i<len; i++)
    Serial.write( c );
}

static void print( int32_t val, int8_t len )
{
  char s[16];
  ltoa( val, s, 10 );
  repeat( ' ', len - strlen(s) );
  Serial.print( s );
}

You have to be careful about how much information you are printing. You can print too much information, and the Arduino will not process GPS characters in time. This causes the input buffer to overflow, and GPS characters will be lost.

The above sketch does 2 things to avoid losing GPS characters:

  1. It doesn't print anything until the while loop is done reading characters; and

  2. It saves a copy of the satellites array for comparison. If you print things while NeoGPS is parsing the satellites array, you can get corrupted satellite data: some data may be from the previous update, and some data may be from the current update, and it may only be half-parsed.

It also compares the satellite IDs, in case the satellite count stayed the same. It may have lost one satellite and started receiving from a new one. The count would be the same, but the IDs are different.

You could even compare the elevation/azimuth/SNR/tracked pieces, in case you are updating a display. The count and the IDs might be the same, but satellites may have moved.

Your original sketch uses 8894 bytes of program space and 669 bytes of RAM.
This version uses 8244 bytes of program space and 662 bytes of RAM.

It saved code space by not using sprintf. It saved RAM space by using the F macro and PROGMEM storage, and then used that RAM space to hold the copy of the satellites array.

Cheers,
/dev

Thank you so much for rewritting my poor sketch.

I have a problem with "Serial << fix.dateTime;" because I ave a number like "552590681" not a time and date.
I do not undestand why.

neutrinos:
I have a problem with "Serial << fix.dateTime;" because I ave a number like "552590681" not a time and date.

Why do you have a string like "552590681" and not the date/time from the fix structure? Where did it come from?

Did you know that the GPS device provides the date and time in several different sentences? It is very accurate. See this table for which sentences provide which pieces. NeoGPS parses those sentences and fills out the fix.dateTime piece. You can print the date/time piece with the streaming operator:

     Serial << fix.dateTime;

The RMC and ZDA sentences provide both date and time; other sentences provide one or the other. As long as your device sends an RMC and you have enabled NMEAGPS_PARSE_RMC in NMEAGPS_cfg.h, it should be filled out for you. Every fix that you get from gps.read() will have the current date/time.

I on(t know why I have number in steed of time and date .

in NMEAGPS_cfg.h begin line 16

#define NMEAGPS_PARSE_GGA
//#define NMEAGPS_PARSE_GLL
//#define NMEAGPS_PARSE_GSA
#define NMEAGPS_PARSE_GSV
//#define NMEAGPS_PARSE_GST
#define NMEAGPS_PARSE_RMC
//#define NMEAGPS_PARSE_VTG
//#define NMEAGPS_PARSE_ZDA

With TinyGPS I can read RMC and GGA, but GSV is not implanted...
I had added a function about summer and winter time from UTC, an other one to give me in my country day date month as "monday 07 august"

I on(t know why I have number in steed of time and date .

Do you mean this code:

    Serial << fix.dateTime;

... prints "552590681" on the Serial Monitor window?

I had added a function about summer and winter time from UTC

There is an example of calculating the Daylight Saving Time offset in NMEAtimezone.ino. It may need to be modified for your country.

an other one to give me in my country day date month as "monday 07 august"

The fix.dateTime is a structure that contains year, month, date (1..31 day of month), hours, minutes and seconds. The day-of-week is called "day". These are all integer values that you would use to index into an array of C strings. For example,

// Month strings
const char jan  [] PROGMEM = "january";
const char feb [] PROGMEM = "february";
  ...
const char dec [] PROGMEM = "december";

const char * const monthNames[] PROGMEM = { jan, feb, ... dec };

const __FlashStringHelper *monthName( uint8_t month ) // 1..12
{
  return CF( pgm_read_ptr( &monthNames[ month-1 ] ) );
}

This would be called to print the month name instead of the month number. For example:

void printDate( const NeoGPS::time_t dt )
{
  dt.set_day(); // calculates the day-of-week

  Serial.print( dayName( dt.day ) );
  Serial.print( ' ' );
  if (dt.date < 10) Serial.print( '0' ); // leading zero
  Serial.print( dt.date );
  Serial.print( ' ' );
  Serial.print( monthName( dt.month ) );      <----
  Serial.println();

} // printDate

void TableSatellitesInView()
{
  nbsat = gps.sat_count;

  int i = 0;

  if (fix.valid.time && fix.valid.date) {
    Serial.print( F("time and date are : ") );

    printTime( fix.dateTime );
    Serial.print( ' ' );
    printDate( fix.dateTime );      <----
  }

See attached program, which includes a USA timezone and DST offset.

Cheers,
/dev

neutrinos.ino (9 KB)

google translate :
This morning I turn on my computer, at the end of the usb cable there is arduino uno which starts alone, I open IDE to see the serial terminal window, and while I did nothing, the date and The hour appear in place of the series of numbers ... Mystery! The main thing is that it works. Awesome !
Thank you so much

I wrote on gogle translate before coming on the forum.
I read your post but not yet tried the skit.
Thank you again for your work.
I learned the Qbasic on an 8086 processor and I also learned COBOL. 3 years later I changed work and I no longer programmed. For my leisure, a few years ago I discovered PHP. I recently started with C with Arduino. That's all.
You are Leonardo da Vinci and I Cromagnon.
It is obvious that you program 1,000,000 times better than me. If sometimes I understand what you are planning, I will never have thought of it. For example

static void repeat( char c, int8_t len )
{
  for (int8_t i=0; i<len; i++)
    Serial.write( c );
}

or

static void print( int32_t val, int8_t len )
{
  char s[16];
  ltoa( val, s, 10 );
  repeat( ' ', len - strlen(s) );
  Serial.print( s );
}

//-----------------
// Month strings

const char jan[] PROGMEM = "january";
const char feb[] PROGMEM = "february";
const char mar[] PROGMEM = "march";
const char apr[] PROGMEM = "april";
const char may[] PROGMEM = "may";
const char jun[] PROGMEM = "june";
const char jul[] PROGMEM = "july";
const char aug[] PROGMEM = "august";
const char sep[] PROGMEM = "september";
const char oct[] PROGMEM = "october";
const char nov[] PROGMEM = "november";
const char dec[] PROGMEM = "december";

const char * const monthNames[] PROGMEM =
  { jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };

const __FlashStringHelper *monthName( uint8_t month ) // 1..12
{
  return CF( pgm_read_ptr( &monthNames[ month-1 ] ) );
}

//-----------------
// Day-of-week strings

const char sun[] PROGMEM = "sunday";
const char mon[] PROGMEM = "monday";
const char tue[] PROGMEM = "tuesday";
const char wed[] PROGMEM = "wednesday";
const char thu[] PROGMEM = "thursday";
const char fri[] PROGMEM = "friday";
const char sat[] PROGMEM = "saturday";

const char * const dayNames[] PROGMEM = { sun, mon, tue, wed, thu, fri, sat };

const __FlashStringHelper *dayName( uint8_t day ) // 1..7
{
  return CF( pgm_read_ptr( &dayNames[ day-1 ] ) );
}


.../...

  Serial.print( monthName( dt.month ) );

.

I moify this

void printTime( const NeoGPS::time_t dt )
{
  Serial.print( dt.hours );
  Serial.print( ':' );
  if (dt.minutes < 10) Serial.print( '0' ); // leading zero
  Serial.print( dt.minutes );
  Serial.print( ':' );
  if (dt.seconds < 10) Serial.print( '0' ); // leading zero
  Serial.print( dt.seconds );

} // printTime

In most of the United States Daylight Saving Time begins at 2:00 a.m. local time on the second Sunday in March. On the first Sunday in November areas on Daylight Saving Time return to Standard Time at 2:00 a.m.

In Europe Daylight Saving Time is commonly referred to as Summer Time. Summer Time begins at 1:00 a.m. UTC (GMT) on the last Sunday in March. On the last Sunday in October areas on Summer Time (Daylight Saving Time) return to Standard Time at 1:00 am UTC (GMT).

I do not understand how can I change for Europe

void adjustTime( NeoGPS::time_t & dt )
{
  NeoGPS::clock_t seconds = dt; // convert the structure pieces to a seconds count

  //  USA Daylight Savings Time rule (calculated once per reset and year!)
  static NeoGPS::time_t  changeover;
  static NeoGPS::clock_t springForward, fallBack;

  if ((springForward == 0) || (changeover.year != fix.dateTime.year)) {
    changeover.year    = fix.dateTime.year;
    changeover.month   = 3;
    changeover.date    = 14; // latest 2nd Sunday
    changeover.hours   = 2;
    changeover.minutes = 0;
    changeover.seconds = 0;
    changeover.set_day();
    // Step back to the 2nd Sunday, if day != SUNDAY
    changeover.date -= (changeover.day - NeoGPS::time_t::SUNDAY);
    springForward = (NeoGPS::clock_t) changeover;

    changeover.month   = 11;
    changeover.date    = 7; // latest 1st Sunday
    changeover.hours   = 2 - 1; // to account for the "apparent" DST +1
    changeover.set_day();
    // Step back to the 1st Sunday, if day != SUNDAY
    changeover.date -= (changeover.day - NeoGPS::time_t::SUNDAY);
    fallBack = (NeoGPS::clock_t) changeover;
  }

  seconds += zone_offset; // offset to the local timezone

  if ((springForward <= seconds) && (seconds < fallBack))
    seconds += NeoGPS::SECONDS_PER_HOUR;

  dt = seconds; // convert back to a date/time structure

} // adjustTime

About Daylight Saving Time, few days ago I write this to verify my DLST function.

//#########################################################################
boolean DLST(int y, byte m, byte d, byte h=2)
{ // before 1976 it is not always last Sunday of March and October at 01h00 UTC 
  byte s = (31 - (5 * y /4 + 4) % 7);  // spring
  byte a = (31 - (5 * y /4 + 1) % 7);  // autumn
  if
  (
    (
      (m > 3)
      &&
      (m < 10)
    )
    ||
    (
      (m == 3)
      &&
      (d > s)
    )
    ||
    (
      (m == 3)
      &&
      (d == s)
      &&
      (h >= 1)
    )
    ||
    (
      (m == 10)
      &&
      (d < a)
    )
    ||
    (
      (m == 10)
      &&
      (d == a)
      &&
      (h < 1)
    )
  )
  {  return true;  }
  else
  {  return false; }
}
//#########################################################################
////////////////////////////////////////////////////////////////////////////////////////
void setup()  
{ Serial.begin(9600);
  while (!Serial);
/* theese dates for Europe come from internet almanach */
  char* t[] = {
"26/03/2000 (GMT+2)",
"29/10/2000 (GMT+1)",
"25/03/2001 (GMT+2)",
"28/10/2001 (GMT+1)",
"31/03/2002 (GMT+2)",
"27/10/2002 (GMT+1)",
"30/03/2003 (GMT+2)",
"26/10/2003 (GMT+1)",
"28/03/2004 (GMT+2)",
"31/10/2004 (GMT+1)",
"27/03/2005 (GMT+2)",
"30/10/2005 (GMT+1)",
"26/03/2006 (GMT+2)",
"29/10/2006 (GMT+1)",
"25/03/2007 (GMT+2)",
"28/10/2007 (GMT+1)",
"30/03/2008 (GMT+2)",
"26/10/2008 (GMT+1)",
"29/03/2009 (GMT+2)",
"25/10/2009 (GMT+1)",
"28/03/2010 (GMT+2)",
"31/10/2010 (GMT+1)",
"27/03/2011 (GMT+2)",
"30/10/2011 (GMT+1)",
"25/03/2012 (GMT+2)",
"28/10/2012 (GMT+1)",
"31/03/2013 (GMT+2)",
"27/10/2013 (GMT+1)",
"30/03/2014 (GMT+2)",
"26/10/2014 (GMT+1)",
"29/03/2015 (GMT+2)",
"25/10/2015 (GMT+1)",
"27/03/2016 (GMT+2)",
"30/10/2016 (GMT+1)",
"26/03/2017 (GMT+2)",
"29/10/2017 (GMT+1)",
"25/03/2018 (GMT+2)",
"28/10/2018 (GMT+1)",
"31/03/2019 (GMT+2)",
"27/10/2019 (GMT+1)",
"29/03/2020 (GMT+2)",
"25/10/2020 (GMT+1)",
"28/03/2021 (GMT+2)",
"31/10/2021 (GMT+1)",
"27/03/2022 (GMT+2)",
"30/10/2022 (GMT+1)",
"26/03/2023 (GMT+2)",
"29/10/2023 (GMT+1)",
"31/03/2024 (GMT+2)",
"27/10/2024 (GMT+1)",
"30/03/2025 (GMT+2)",
"26/10/2025 (GMT+1)",
"29/03/2026 (GMT+2)",
"25/10/2026 (GMT+1)",
"28/03/2027 (GMT+2)",
"31/10/2027 (GMT+1)",
"26/03/2028 (GMT+2)",
"29/10/2028 (GMT+1)",
"25/03/2029 (GMT+2)",
"28/10/2029 (GMT+1)",
"31/03/2030 (GMT+2)",
"27/10/2030 (GMT+1)",
"30/03/2031 (GMT+2)",
"26/10/2031 (GMT+1)",
"28/03/2032 (GMT+2)",
"31/10/2032 (GMT+1)",
"27/03/2033 (GMT+2)",
"30/10/2033 (GMT+1)",
"26/03/2034 (GMT+2)",
"29/10/2034 (GMT+1)",
"25/03/2035 (GMT+2)",
"28/10/2035 (GMT+1)",
"30/03/2036 (GMT+2)",
"26/10/2036 (GMT+1)",
"29/03/2037 (GMT+2)",
"25/10/2037 (GMT+1)"
};
  byte s, a, c, i = 0;
  int y;
  for(byte j = 0 ; j < sizeof(t)/(2 * sizeof(t[0])) ; j++)
  {  y = 2000 + j;
     s = (31 - (5 * y /4 + 4) % 7);  // spring
     c = DLST(y,3,s);
     Serial.print(t[i++]); Serial.print("  Date: "); Serial.print(s); Serial.print("/03/"); Serial.print(y); Serial.print(" (GMT + ");Serial.print(1 + c);Serial.println(")");
     a = (31 - (5 * y /4 + 1) % 7);  // autumn
     c = DLST(y,10,a);
     Serial.print(t[i++]); Serial.print("  Date: "); Serial.print(a); Serial.print("/10/"); Serial.print(y); Serial.print(" (GMT + ");Serial.print(1 + c);Serial.println(")");
  }
}
////////////////////////////////////////////////////////////////////////////////////////
void loop() 
{ delay(1000);
}
////////////////////////////////////////////////////////////////////////////////////////

after I add this function (in 6 lnes) in my sketch using TinyGPS.
I use it each time I need display time and date on my tft screen (twice per second).

During waintig 3D fix location, I want display GSV signals in bargraph on my TFT sreen. If I loose some frame, it is not important.
After, just display local date and time, localisation, speed, altitude

With your librairy I discover an other univers about programming and I will rewrite/optimise my code with Oriented Object Programming.
Thank you very much for opening my mind.

wainting3Dfix.jpg

I do not understand how can I change for Europe

Here's a snippet that shows how to choose USA/EU DST rules. I'll update NMEAtimezone.ino to have this feature, too:

// Uncomment one DST changeover rule, or define your own:
#define USA_DST
//#define EU_DST

#if defined(USA_DST)
  static const uint8_t springMonth =  3;
  static const uint8_t springDate  = 14; // latest 2nd Sunday
  static const uint8_t springHour  =  2;
  static const uint8_t fallMonth   = 11;
  static const uint8_t fallDate    =  7; // latest 1st Sunday
  static const uint8_t fallHour    =  2;
  #define CALCULATE_DST

#elif defined(EU_DST)
  static const uint8_t springMonth =  3;
  static const uint8_t springDate  = 31; // latest last Sunday
  static const uint8_t springHour  =  1;
  static const uint8_t fallMonth   = 10;
  static const uint8_t fallDate    = 31; // latest last Sunday
  static const uint8_t fallHour    =  1;
  #define CALCULATE_DST
#endif

//--------------------------

void adjustTime( NeoGPS::time_t & dt )
{
  NeoGPS::clock_t seconds = dt; // convert date/time structure to seconds

  #ifdef CALCULATE_DST
    //  Calculate DST changeover times once per reset and year!
    static NeoGPS::time_t  changeover;
    static NeoGPS::clock_t springForward, fallBack;

    if ((springForward == 0) || (changeover.year != dt.year)) {

      //  Calculate the spring changeover time (seconds)
      changeover.year    = dt.year;
      changeover.month   = springMonth;
      changeover.date    = springDate;
      changeover.hours   = springHour;
      changeover.minutes = 0;
      changeover.seconds = 0;
      changeover.set_day();
      // Step back to a Sunday, if day != SUNDAY
      changeover.date -= (changeover.day - NeoGPS::time_t::SUNDAY);
      springForward = (NeoGPS::clock_t) changeover;

      //  Calculate the fall changeover time (seconds)
      changeover.month   = fallMonth;
      changeover.date    = fallDate;
      changeover.hours   = fallHour - 1; // to account for the "apparent" DST +1
      changeover.set_day();
      // Step back to a Sunday, if day != SUNDAY
      changeover.date -= (changeover.day - NeoGPS::time_t::SUNDAY);
      fallBack = (NeoGPS::clock_t) changeover;
    }
  #endif

  //  First, offset from UTC to the local timezone
  seconds += zone_offset;

  #ifdef CALCULATE_DST
    //  Then add an hour if DST is in effect
    if ((springForward <= seconds) && (seconds < fallBack))
      seconds += NeoGPS::SECONDS_PER_HOUR;
  #endif

  dt = seconds; // convert seconds back to a date/time structure

} // adjustTime

Full NMEAtimezone.ino attached below.

While waiting for a 3D fix location, I want display GSV signals in bargraph on my TFT sreen.

Image embedded for our convenience:

wainting3Dfix.jpg

Technique described here. That's a nice display!

after I add this function (in 6 lnes) in my sketch... I use it each time I need display time and date

Yes, that's an interesting formula to calculate the day. But to convert a UTC time to a CET/CDT time, you would also need to perform "calendar" math. That's what the NeoGPS date/time provides: the correct local date and time, even if the timezone/DST offset pushes the UTC time into a completely different day, month or even year.

For example, a UTC date/time of 31-DEC-2017 23:45:00 should get offset to a CET date/time of 1-JAN-2018 00:45:00. I don't know if your sketch ever displays the day/month/year. If it does, it may not display the correct local day/month/year at certain boundaries.

Cheers,
/dev


P.S. Here's your test sketch with the matching NeoGPS date/time calculations.

NMEAtimezone.ino (6.74 KB)

NeoDLST.ino (6.29 KB)

google translate :
Of course, as I begin, I am much less structured and thoughtful than you are. I miss a step back.
Without knowing the extent of the arduino's capabilities, I started with a UNO and a TFT display and simply display figures, with a delay (1000).
Conscious of the lack of precision, I used a RTC module.
Then, wishing for an automatic change of time, I hesitated between GSM (SIM disabled) and DCF77, then I opted for GPS.
With the GPS new possibilities come to me. I progress slowly. As my sketch evolved and expanded in functions according to my personal needs and my research on the web.
I planned to look at optimization, speed of execution, memory management, etc ...
The UNO becoming too small, I ordered a MEGA.
With your bookstore, I am a bit unsettled because I do not understand how it works and I have difficulty using it well.
Your example will allow other people (as novice as me) to adapt NeoGPS to his country, for example: australia Australia Time Zones - Australia Current Time
Thanks again for your listening, your curiosity, your availability and your work.

-dev:
wainting3Dfix.jpg

That's a nice display!

Mine is not so nice ...

How can I define "In Use" ?

"In View" is maybe "gps.sat_count"...

"In View" is maybe "gps.sat_count"

Yes.

How can I define "In Use" ?

fix.satellites (if GGA or GSA is enabled), or count how many satellites in the array are being "tracked":

  uint8_t inUse = 0;
  for (uint8_t i=0; i < gps.sat_count; i++)
    if (gps.satellites[i].tracked)
      inUse++;

Thank you for your answer.

On my gps, I have :
1)
"no fix", "2D" and "3D", what is the difference ? Maybe number of "in use" ?
2)
some gps id have good gps sdr, but only gray color and latter gray become red or yellow or green, what is the difference ? Maybe completed or not completed sentence from NMEA about the gps id ?