Help with GPS data extraction

HI everyone

I am new to Arduino so please be gentle with me.

I am working on trying to transmit a rtty signal using an ad9850 board. I can successfully transmit some ext by using the following commands

char MM1[41] = " RYRYRYRY THIS IS VK3PB TESTING *** ";
rtty_txstring(MM1);

I am not sure whether rtty_txstring is a function or command but when I feed it the char variable above, it transmits it as rtty.

I have also used the TinyGPS++ library and in particular the Full Example which is reproduced below. My GPS works well with the code.

For the last week I have been trying to extract the latitude variable so that I can transmit it using the rtty_txstring function. The latitude has six digits after the decimal point.

However I have been unable to get the latitude into a form that is acceptable for transmission is as a char variable.

Can anyone explain what I need to do to extract the latitude and get it into a char variable? I should add that I'm using an Arduino Uno.

Thanks Peter

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
   This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;

// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);

void setup()
{
  Serial.begin(115200);
  ss.begin(GPSBaud);

  Serial.println(F("FullExample.ino"));
  Serial.println(F("An extensive example of many interesting TinyGPS++ features"));
  Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
  Serial.println(F("by Mikal Hart"));
  Serial.println();
  Serial.println(F("Sats HDOP Latitude   Longitude   Fix  Date       Time     Date Alt    Course Speed Card  Distance Course Card  Chars Sentences Checksum"));
  Serial.println(F("          (deg)      (deg)       Age                      Age  (m)    --- from GPS ----  ---- to London  ----  RX    RX        Fail"));
  Serial.println(F("---------------------------------------------------------------------------------------------------------------------------------------"));
}

void loop()
{
  static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;

  printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
  printInt(gps.hdop.value(), gps.hdop.isValid(), 5);
  printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
  printFloat(gps.location.lng(), gps.location.isValid(), 12, 6);
  printInt(gps.location.age(), gps.location.isValid(), 5);
  printDateTime(gps.date, gps.time);
  printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2);
  printFloat(gps.course.deg(), gps.course.isValid(), 7, 2);
  printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
  printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.value()) : "*** ", 6);

  unsigned long distanceKmToLondon =
    (unsigned long)TinyGPSPlus::distanceBetween(
      gps.location.lat(),
      gps.location.lng(),
      LONDON_LAT, 
      LONDON_LON) / 1000;
  printInt(distanceKmToLondon, gps.location.isValid(), 9);

  double courseToLondon =
    TinyGPSPlus::courseTo(
      gps.location.lat(),
      gps.location.lng(),
      LONDON_LAT, 
      LONDON_LON);

  printFloat(courseToLondon, gps.location.isValid(), 7, 2);

  const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);

  printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6);

  printInt(gps.charsProcessed(), true, 6);
  printInt(gps.sentencesWithFix(), true, 10);
  printInt(gps.failedChecksum(), true, 9);
  Serial.println();
  
  smartDelay(1000);

  if (millis() > 5000 && gps.charsProcessed() < 10)
    Serial.println(F("No GPS data received: check wiring"));
}

// This custom version of delay() ensures that the gps object
// is being "fed".
static void smartDelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    while (ss.available())
      gps.encode(ss.read());
  } while (millis() - start < ms);
}

static void printFloat(float val, bool valid, int len, int prec)
{
  if (!valid)
  {
    while (len-- > 1)
      Serial.print('*');
    Serial.print(' ');
  }
  else
  {
    Serial.print(val, prec);
    int vi = abs((int)val);
    int flen = prec + (val < 0.0 ? 2 : 1); // . and -
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
    for (int i=flen; i<len; ++i)
      Serial.print(' ');
  }
  smartDelay(0);
}

static void printInt(unsigned long val, bool valid, int len)
{
  char sz[32] = "*****************";
  if (valid)
    sprintf(sz, "%ld", val);
  sz[len] = 0;
  for (int i=strlen(sz); i<len; ++i)
    sz[i] = ' ';
  if (len > 0) 
    sz[len-1] = ' ';
  Serial.print(sz);
  smartDelay(0);
}

static void printDateTime(TinyGPSDate &d, TinyGPSTime &t)
{
  if (!d.isValid())
  {
    Serial.print(F("********** "));
  }
  else
  {
    char sz[32];
    sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
    Serial.print(sz);
  }
  
  if (!t.isValid())
  {
    Serial.print(F("******** "));
  }
  else
  {
    char sz[32];
    sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
    Serial.print(sz);
  }

  printInt(d.age(), d.isValid(), 5);
  smartDelay(0);
}

static void printStr(const char *str, int len)
{
  int slen = strlen(str);
  for (int i=0; i<len; ++i)
    Serial.print(i<slen ? str[i] : ' ');
  smartDelay(0);
}

I am not sure whether rtty_txstring is a function or command but when I feed it the char variable above, it transmits it as rtty.

There are no commands in C or C++, so that doesn't leave much choice.

  smartDelay(1000);

is anything BUT a smart way to read GPS data. The GPS data sends data when it has data, usually about once a second. Spending one second reading any available data is not the best use of resources.

Read whatever data is available, in loop(), passing it to the encode() method. Deal with the results when encode() says the data is complete.

Can anyone explain what I need to do to extract the latitude and get it into a char variable?

You can NOT fit the latitude data in a char variable. The function does not expect a char variable, so this is not really a problem.

You can get the latitude in a char ARRAY, which is what the function wants, so that would work.

The latitude is in gps.location.lat, which is a float, so your assertion that it has 6 digits after the decimal point is wrong. But, you can convert the float to a string using dtostrf().

Paul

The smartdelay command was part of the rtty program I am trying to modify.

I am simply trying to use the program to send some data as rtty I have extracted from my GPS.

Here is my latest combined code

#include <TinyGPS++.h>
#include <stdlib.h>
#include <SoftwareSerial.h>

static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;


// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
/*
   This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   9600-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/


/*RTTY transimitter for AD9850
Stefano Lande IS0EIR
Distribuited under GNU GPL
Based on:
Baudot code by Tim Zaman http://www.timzaman.nl/?p=138
AD9850 by ElecFreaks
*/
#include "EF_AD9850.h"
#include <stdint.h>
/*----------------------------------------------------------------------*/
/*Transmission parameters*/
//TX frequency (MHZ - e6)
#define FREQ 13.600e6
// offset RTTY
#define OFFSET 170
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
/*AD9850 - Arduino wiring*/
//CLK - D11, FQ - D10, DATA - D9, RST - D8
#define CLK 8
#define FQ 9
#define DATA 10
#define RST 11
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
/*Baudot code definitions*/
#define ARRAY_LEN 32
#define LETTERS_SHIFT 31
#define FIGURES_SHIFT 27
#define LINEFEED 2
#define CARRRTN 8
#define is_lowercase(ch) ((ch) >= 'a' && (ch) <= 'z')
#define is_uppercase(ch) ((ch) >= 'A' && (ch) <= 'Z')
unsigned long time;
char letters_arr[33] = "\000E\nA SIU\rDRJNFCKTZLWHYPQOBG\000MXV\000";
char figures_arr[33] = "\0003\n- \a87\r$4',!:(5\")2#6019?&\000./;\000";
enum baudot_mode {
NONE,
LETTERS,
FIGURES
};
/*----------------------------------------------------------------------*/
//AD9850 object
EF_AD9850 AD9850(CLK, FQ, DATA, RST);


void setup()
{
//AD9850 initialize and reset
AD9850.init();
AD9850.reset();

static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
  

char *latitude;
char MM1[41] = " RYRYRYRY THIS IS VK3PB TESTING *** ";



void loop()
  {
  ss.begin(GPSBaud);  //start receiving gps data;
  char tmp [20] = "latitude = ";
  dtostrf(gps.location.lat(),10,6, &tmp[10]);
  ss.end();//close down gps so that id doesn't interfere with rtty timing
  
  rtty_txstring(tmp); //send tmp as rtty
  rtty_txstring(MM1); //send MM1 as rtty
  
}







// This custom version of delay() ensures that the gps object
// is being "fed".
static void smartDelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    while (ss.available())
      gps.encode(ss.read());
  } while (millis() - start < ms);
}

static void printFloat(float val, bool valid, int len, int prec)
{
  if (!valid)
  {
    while (len-- > 1)
      Serial.print('*');
    Serial.print(' ');
  }
  else
  {
    Serial.print(val, prec);
    int vi = abs((int)val);
    int flen = prec + (val < 0.0 ? 2 : 1); // . and -
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
    for (int i=flen; i<len; ++i)
      Serial.print(' ');
  }
  smartDelay(0);
}

static void printInt(unsigned long val, bool valid, int len)
{
  char sz[32] = "*****************";
  if (valid)
    sprintf(sz, "%ld", val);
  sz[len] = 0;
  for (int i=strlen(sz); i<len; ++i)
    sz[i] = ' ';
  if (len > 0) 
    sz[len-1] = ' ';
  Serial.print(sz);
  smartDelay(0);
}

static void printDateTime(TinyGPSDate &d, TinyGPSTime &t)
{
  if (!d.isValid())
  {
    Serial.print(F("********** "));
  }
  else
  {
    char sz[32];
    sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
    Serial.print(sz);
  }
  
  if (!t.isValid())
  {
    Serial.print(F("******** "));
  }
  else
  {
    char sz[32];
    sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
    Serial.print(sz);
  }

  printInt(d.age(), d.isValid(), 5);
  smartDelay(0);
}

static void printStr(const char *str, int len)
{
  int slen = strlen(str);
  for (int i=0; i<len; ++i)
    Serial.print(i<slen ? str[i] : ' ');
  smartDelay(0);
}




//RTTY functions
/*----------------------------------------------------------------------*/
uint8_t char_to_baudot(char c, char *array)
{
int i;
for (i = 0; i < ARRAY_LEN; i++)
{
if (array[i] == c)
return i;
}
return 0;
}



void rtty_txbyte(uint8_t b)
{
int8_t i;
rtty_txbit(0);
/* TODO: I don't know if baudot is MSB first or LSB first */
/* for (i = 4; i >= 0; i--) */
for (i = 0; i < 5; i++)
{
if (b & (1 << i))
rtty_txbit(1);
else
rtty_txbit(0);
}
rtty_txbit(1);
}


void rtty_txstring(char *str)
{
enum baudot_mode current_mode = NONE;
char c;
uint8_t b;
while (*str != '\0')
{
c = *str;
/* some characters are available in both sets */
if (c == '\n')
{
rtty_txbyte(LINEFEED);
}
else if (c == '\r')
{
rtty_txbyte(CARRRTN);
}
else if (is_lowercase(*str) || is_uppercase(*str))
{
if (is_lowercase(*str))
{
c -= 32;
}
if (current_mode != LETTERS)
{
rtty_txbyte(LETTERS_SHIFT);
current_mode = LETTERS;
}
rtty_txbyte(char_to_baudot(c, letters_arr));
}
else
{
b = char_to_baudot(c, figures_arr);
if (b != 0 && current_mode != FIGURES)
{
rtty_txbyte(FIGURES_SHIFT);
current_mode = FIGURES;
}
rtty_txbyte(b);
}
str++;
}
}
// Transmit a bit as a mark or space
void rtty_txbit (int bit) {
if (bit) {
// High - mark
//digitalWrite(2, HIGH);
//digitalWrite(3, LOW);
AD9850.wr_serial(0x00, FREQ+OFFSET);
}
else {
// Low - space
//digitalWrite(3, HIGH);
//digitalWrite(2, LOW);
AD9850.wr_serial(0x00, FREQ);
}
// Delay appropriately - tuned to 45.45 baud.
delay(22); //sets the baud rate
//delayMicroseconds(250);
}

char *dtostrf (double val, signed char width, unsigned char prec, char *sout) {
  char fmt[20];
  sprintf(fmt, "%%%d.%df", width, prec);
  sprintf(sout, fmt, val);
  return sout;
}

I've tried to incorporate your suggested changes but this is the output I am getting now

LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING 
LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING 
LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING 
LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING 
LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING 
LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING 
LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING  LATITUDE          B RYRYRYRY THIS IS VK3PB TESTING

As you can see I am still having problems getting the latitude variable into a form that the rtty function will accept.

If only the Arduino understood python, life would be so much easier...

cheers Peter

dtostrf(gps.location.lat(),10,6, &tmp[10]);

What is in tmp after this function call? Is it what you think it should be?

When do you ever actually read the GPS now?

That's a very good question Paul! Problem is I have no idea how to find out.

You see, I have previously programmed in Python. The IDE for python allows for real tiem commands to be sent and processed. SO I could test the output of a variable to see what type it is.

As far as I can see the IDE for the Arduino's C language doesn't seem to allow me to send commands and have then processed in real time. I have to make them into a sketch and upload it.

As to reading the GPS, I thought that givng the command

dtostrf(gps.location.lat(),10,6, &tmp[10]);

would cause the Arduino to go and fetch the variable gps.location.lat() from the GPS?

cheers Peter

Problem is I have no idea how to find out.

Serial.print("tmp = [");
Serial.print(tmp);
Serial.println("]");
As to reading the GPS, I thought that givng the command

 dtostrf(gps.location.lat(),10,6, &tmp[10]);

would cause the Arduino to go and fetch the variable gps.location.lat() from the GPS?

No. It causes the lat() method to get the data from the location instance of the gps instance. Where are those instances getting data? They used to get data from the encode() method of the gps instance. That data came from reading data from the serial port that the GPS was connected to. That happened in the stupidly named smartDelay() method. You no longer read from the GPS, so lat() will never have any data to return.

OK I have modified my code as follows to exclude (for the time being) the rtty transmission, to call the Smartdelay routine to that encode () has some data to work with and then to print it outi n the manner you have specified.

void loop()
  {
  
  ss.begin(GPSBaud);  //start receiving gps data;
  char tmp [20] = "latitude = ";
  dtostrf(gps.location.lat(),10,6, &tmp[10]);
//  ss.end();//close down gps so that id doesn't interfere with rtty timing
  smartDelay(1000);//use this peculiarly named routine  

  Serial.print("tmp = [");
  Serial.print(tmp);
  Serial.println("]");

//  rtty_txstring(tmp); //send tmp as rtty
//  rtty_txstring(MM1); //send MM1 as rtty

and this is the result

tmp = [latitude = ?]
tmp = [latitude = ?]
tmp = [latitude = ?]
tmp = [latitude = ?]
tmp = [latitude = ?]
tmp = [latitude = ?]
tmp = [latitude = ?]
tmp = [latitude = ?]

I then tried to alter the code to the following

void loop()
  {
  
  ss.begin(GPSBaud);  //start receiving gps data;
  char tmp [20] = "latitude = ";
  dtostrf(gps.location.lat(),10,6, &tmp[10]);
//  ss.end();//close down gps so that id doesn't interfere with rtty timing
  smartDelay(1000);
  Serial.print("tmp = [");
  Serial.print(tmp);
  Serial.println("]");
  printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
  
//  rtty_txstring(tmp); //send tmp as rtty
//  rtty_txstring(MM1); //send MM1 as rtty

And this was the result

-37.846786 tmp = [latitude = ?]
-37.846786 tmp = [latitude = ?]
-37.846786 tmp = [latitude = ?]
-37.846786 tmp = [latitude = ?]
-37.846786 tmp = [latitude = ?]
-37.846786 tmp = [latitude = ?]
-37.846786 tmp = [latitude = ?]
-37.846786 tmp = [latitude = ?]

So it looks like I have data that is there to be extracted. I'm just not extracting it properly.

  char tmp [20] = "latitude = ";
  dtostrf(gps.location.lat(),10,6, &tmp[10]);

Try writing JUST the lat value to the array.

  char tmp [20] = "latitude = ";
  dtostrf(gps.location.lat(),10,6, tmp);

OK ahere's my amended cod

void loop()
  {
  
  ss.begin(GPSBaud);  //start receiving gps data;
  char tmp [20] = "latitude = ";
  dtostrf(gps.location.lat(),10,6, tmp);
//  ss.end();//close down gps so that id doesn't interfere with rtty timing
  smartDelay(1000);
  Serial.print("tmp = [");
  Serial.print(tmp);
  Serial.println("]");
  
//  rtty_txstring(tmp); //send tmp as rtty
//  rtty_txstring(MM1); //send MM1 as rtty

and the result from the serial monitor

tmp = [ ?]
tmp = [ ?]
tmp = [ ?]
tmp = [ ?]
tmp = [ ?]
tmp = [ ?]
tmp = [ ?]
tmp = [ ?]
tmp = [ ?]
tmp = [ ?]
tmp = [ ?]
tmp = [ ?]
tmp = [ ?]

cheers Peter

You are STILL assuming that you have valid GPS data. Stop that. Do NOT call dtostrf() outside of the if(gps.encode()) block.

Print the value returned by gps.location.lat(), before calling dtostrf() too.

I have applied your second suggestion as follows

void loop()
  {
  
  ss.begin(GPSBaud);  //start receiving gps data;
  char tmp [20] = "latitude = ";
  printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
  dtostrf(gps.location.lat(),10,6, tmp);
//  ss.end();//close down gps so that id doesn't interfere with rtty timing
  smartDelay(1000);
  Serial.print("tmp = [");
  Serial.print(tmp);
  Serial.println("]");
  
//  rtty_txstring(tmp); //send tmp as rtty
//  rtty_txstring(MM1); //send MM1 as rtty

giving the output

********** tmp = [ ?]
-37.846817 tmp = [ ?]
-37.846817 tmp = [ ?]
-37.846817 tmp = [ ?]
-37.846817 tmp = [ ?]
-37.846817 tmp = [ ?]
-37.846817 tmp = [ ?]
-37.846817 tmp = [ ?]
-37.846817 tmp = [ ?]
-37.846817 tmp = [ ?]
-37.846817

Next

You are STILL assuming that you have valid GPS data. Stop that. Do NOT call dtostrf() outside of the if(gps.encode()) block.

I went back and look through the original Fullexample code to see where the if(gps.encode()) block block was.

The only mention of encode I can find is in the Smartdelay function ie

static void smartDelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    while (ss.available())
      gps.encode(ss.read());
  } while (millis() - start < ms)

There is no IF statement in there. Do you want me to call dtostrf() in this function. If not where?

There is no IF statement in there.

That's one of the reasons why that is such a piss-poor function.

Do you want me to call dtostrf() in this function. If not where?

Yes. But, first, I want you to upload this code to the Arduino.

void setup()
{
  float pi = 3.14159;
  char pie[20] = "some useless crap";
  dtostrf(pi, 10, 6, pie);
  
  Serial.begin(115200);
  Serial.print("Pie: [");
  Serial.print(pie);
  Serial.println("]");
}

void loop()
{
}

What do you see in the Serial Monitor?

Yes. But, first, I want you to upload this code to the Arduino.

Sure. I uploaded the code and this is what came up on the serial monitor:

Syntax error 1001: Please trash me and buy something that runs Python

Seriously though, the output was

Pie: [  3.141590]

Seriously though, the output was

OK. So, we know that dtostrf() is working.

Next step:

static void smartDelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    while (ss.available())
    {
      if(gps.encode(ss.read())
      {
         char tmp[20];
         dtostrf(gps.location.lat(), 10, 6, tmp);
         Serial.print("lat: [");
         Serial.println(gps.location.lat());

         Serial.print("tmp: [");
         Serial.print(tmp);
         Serial.println("]");
      }
    }
  } while (millis() - start < ms)

This is what I got

You've also got the only copy of the code in existence...

Ah I see, you left some brackets off. NO matter.

This is the code as it now stands (excluding later functions as otherwise it exceeds the length allowed)

#include <TinyGPS++.h>
#include <stdlib.h>
#include <SoftwareSerial.h>

static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;


// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
/*
   This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/


/*RTTY transimitter for AD9850
Stefano Lande IS0EIR
Distribuited under GNU GPL
Based on:
Baudot code by Tim Zaman http://www.timzaman.nl/?p=138
AD9850 by ElecFreaks
*/
#include "EF_AD9850.h"
#include <stdint.h>
/*----------------------------------------------------------------------*/
/*Transmission parameters*/
//TX frequency (MHZ - e6)
#define FREQ 13.600e6
// offset RTTY
#define OFFSET 170
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
/*AD9850 - Arduino wiring*/
//CLK - D11, FQ - D10, DATA - D9, RST - D8
#define CLK 8
#define FQ 9
#define DATA 10
#define RST 11
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
/*Baudot code definitions*/
#define ARRAY_LEN 32
#define LETTERS_SHIFT 31
#define FIGURES_SHIFT 27
#define LINEFEED 2
#define CARRRTN 8
#define is_lowercase(ch) ((ch) >= 'a' && (ch) <= 'z')
#define is_uppercase(ch) ((ch) >= 'A' && (ch) <= 'Z')
unsigned long time;
char letters_arr[33] = "\000E\nA SIU\rDRJNFCKTZLWHYPQOBG\000MXV\000";
char figures_arr[33] = "\0003\n- \a87\r$4',!:(5\")2#6019?&\000./;\000";
enum baudot_mode {
NONE,
LETTERS,
FIGURES
};
/*----------------------------------------------------------------------*/
//AD9850 object
EF_AD9850 AD9850(CLK, FQ, DATA, RST);


void setup()
{
//AD9850 initialize and reset
AD9850.init();
AD9850.reset();


Serial.begin(115200);
//  ss.begin(GPSBaud);
//
//  Serial.println(F("FullExample.ino"));
//  Serial.println(F("An extensive example of many interesting TinyGPS++ features"));
//  Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
//  Serial.println(F("by Mikal Hart"));
//  Serial.println();
//  Serial.println(F("Sats HDOP Latitude   Longitude   Fix  Date       Time     Date Alt    Course Speed Card  Distance Course Card  Chars Sentences Checksum"));
//  Serial.println(F("          (deg)      (deg)       Age                      Age  (m)    --- from GPS ----  ---- to London  ----  RX    RX        Fail"));
//  Serial.println(F("---------------------------------------------------------------------------------------------------------------------------------------"));
}

char MM1[41] = " RYRYRYRY THIS IS VK3PB TESTING *** ";  

void loop()
  {
  
  ss.begin(GPSBaud);  //start receiving gps data;
  char tmp [20] = "latitude = ";
  dtostrf(gps.location.lat(),10,6, tmp);
//  ss.end();//close down gps so that id doesn't interfere with rtty timing
  smartDelay(1000);
  Serial.print("tmp = [");
  Serial.print(tmp);
  Serial.println("]");
  
//  rtty_txstring(tmp); //send tmp as rtty
//  rtty_txstring(MM1); //send MM1 as rtty


  
  
  
  
//  printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
//  printInt(gps.hdop.value(), gps.hdop.isValid(), 5);
//  printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
//  printFloat(gps.location.lng(), gps.location.isValid(), 12, 6);
//  printInt(gps.location.age(), gps.location.isValid(), 5);
//  printDateTime(gps.date, gps.time);
//  printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2);
//  printFloat(gps.course.deg(), gps.course.isValid(), 7, 2);
//  printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
//  printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.value()) : "*** ", 6);

//  unsigned long distanceKmToLondon =
//    (unsigned long)TinyGPSPlus::distanceBetween(
//      gps.location.lat(),
//      gps.location.lng(),
//      LONDON_LAT, 
//      LONDON_LON) / 1000;
//  printInt(distanceKmToLondon, gps.location.isValid(), 9);
//
//  double courseToLondon =
//    TinyGPSPlus::courseTo(
//      gps.location.lat(),
//      gps.location.lng(),
//      LONDON_LAT, 
//      LONDON_LON);
//
//  printFloat(courseToLondon, gps.location.isValid(), 7, 2);
//
//  const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);
//
//  printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6);
//
//  printInt(gps.charsProcessed(), true, 6);
//  printInt(gps.sentencesWithFix(), true, 10);
//  printInt(gps.failedChecksum(), true, 9);
//  Serial.println();
//  
//  smartDelay(1000);
//
//  if (millis() > 5000 && gps.charsProcessed() < 10)
//    Serial.println(F("No GPS data received: check wiring"));
}








// This custom version of delay() ensures that the gps object
// is being "fed".
static void smartDelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    while (ss.available())
      gps.encode(ss.read());
      if(gps.encode(ss.read()))
        {
        char tmp[20];
        dtostrf(gps.location.lat(), 10, 6, tmp);
        Serial.print("lat: [");
        Serial.println(gps.location.lat());

        Serial.print("tmp: [");
        Serial.print(tmp);
        Serial.println("]");
      }
  } while (millis() - start < ms);
}

static void printFloat(float val, bool valid, int len, int prec)
{
  if (!valid)
  {
    while (len-- > 1)
      Serial.print('*');
    Serial.print(' ');
  }
  else
  {
    Serial.print(val, prec);
    int vi = abs((int)val);
    int flen = prec + (val < 0.0 ? 2 : 1); // . and -
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
    for (int i=flen; i<len; ++i)
      Serial.print(' ');
  }
  smartDelay(0);
}

...

and this is the output after making your changes

tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
lat: [-37.85
tmp: [         ?]
tmp = [         ?]
lat: [-37.85
tmp: [         ?]
tmp = [         ?]
tmp = [         ?]
lat: [-37.85
tmp: [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]
lat: [-37.85
tmp: [         ?]
tmp = [         ?]
tmp = [         ?]
tmp = [         ?]

and this is the output after making your changes

You should have deleted the call to dtostrf() and the Serial.print() statements from loop. As you can see, they never produce anything useful.

Then, change
char tmp[20];
dtostrf(gps.location.lat(), 10, 6, tmp);
to

        char tmp[20];
        float lat = gps.location.lat();
        dtostrf(lat, 10, 6, tmp);

Ok code changed to

void loop()
  {
  
  ss.begin(GPSBaud);  //start receiving gps data;
  char tmp[20]; 
  smartDelay(1000);
  
}


and

static void smartDelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    while (ss.available())
      gps.encode(ss.read());
      if(gps.encode(ss.read()))
        {
        char tmp[20];
        float lat = gps.location.lat();
        dtostrf(lat, 10, 6, tmp);
        Serial.print("lat: [");
        Serial.println(gps.location.lat());

        Serial.print("tmp: [");
        Serial.print(tmp);
        Serial.println("]");
      }
  } while (millis() - start < ms);
}

with the following result

lat: [-37.85
tmp: [         ?]
lat: [-37.85
tmp: [         ?]
lat: [-37.85
tmp: [         ?]
lat: [-37.85
tmp: [         ?]

but the output is very slow (takes 10-15 seconds before a new update is printed
.

Why are you calling the begin() method in loop()? It should be called once, in setup().

I have no idea why the code is not producing the expected output. Try changing the Serial.print(gps.location.lat()) statement to Serial.print(lat). Maybe that will tell us something.

@vk3pb,

The problem here is that the code posted in response 2 contains a invalid "roll-your-own" version of dtostrf:

char *dtostrf (double val, signed char width, unsigned char prec, char *sout) {
  char fmt[20];
  sprintf(fmt, "%%%d.%df", width, prec);
  sprintf(sout, fmt, val);
  return sout;
}

On AVR variants of Arduino, the sprintf("%f") variants are not implemented, which explains the appearance of the "?" in the output stream.

Happily, response 12 seems to show that dtostrf is provided natively, so getting over this little hump may be as easy as deleting the above code block.

@PaulS, I welcome your proposal for a mechanism that provides the convenience of delay() while preventing the overflow of the GPS stream--one that isn't as "stupidly named" as my "piss poor" SmartDelay().