I created a couple subroutines to compress and decompress GPS data so I can send it over my LoRa radios. Unfortunately, I cannot get sprintf to work correctly in this case. If I use a String and then the .toCharArray function everything works correctly. I've tested and Googled for days now so I'm finally reaching out. What am I doing incorrectly?
The fractional part of the GPS coordinate frequently gets corrupted when using sprintf in line 98. When wrong, the error is always too low by 65537. I assume this is a clue but can't figure it out.
The commented out String part (line 72 to 96) will work exactly as desired. It's there for reference.
The For loop in setup() is for testing purposes only.
float mylatitude;
float mylongitude;
char gpsdata[9];
String myString;
float receivedlatitude;
float receivedlongitude;
void setup() {
Serial.begin(38400);
randomSeed(analogRead(0));
long test;
//for testing purposes only
for (int mytest = 0; mytest < 1000; mytest++) {
test = random(0, 180000);
mylongitude = (float)test / 1000.0;
test = random(0, 90000);
mylatitude = (float)test / 1000.0;
if (random(0, 2) == 1) {
mylongitude = -mylongitude;
}
if (random(0, 2) == 1) {
mylatitude = -mylatitude;
}
Serial.print(F("sent:"));
Serial.print(mylatitude, 5);
Serial.print(":");
Serial.println(mylongitude, 5);
gpscompressor();
gpsdecompressor();
Serial.print(F("recv:"));
Serial.print(receivedlatitude, 5);
Serial.print(":");
Serial.println(receivedlongitude, 5);
Serial.println("");
}
}
void loop() {
// put your main code here, to run repeatedly:
}
void gpscompressor() {
gpscompress(mylatitude, 0);
gpscompress(mylongitude, 4);
}
void gpscompress(float gps_coordinate, uint8_t x) {
uint8_t signvalue = 0;
long fractionalpart;
char tempdata[7]; //check length
uint8_t char1;
uint8_t char2;
if (gps_coordinate < 0) {
signvalue = 1; //if positive then 0. if negative then 1
gps_coordinate = -gps_coordinate;
}
gpsdata[x] = (int)gps_coordinate; //stores integer portion of coordinate
fractionalpart = ((float)gps_coordinate - (int)gps_coordinate) * 100000;
//This works well but uses a String
/*
if (fractionalpart >= 10000) {
myString = (String)fractionalpart;
}
else if (fractionalpart >= 1000)
{
myString = "0" + (String)fractionalpart;
}
else if (fractionalpart >= 100)
{
myString = "00" + (String)fractionalpart;
}
else if (fractionalpart >= 10)
{
myString = "000" + (String)fractionalpart;
}
else if (fractionalpart >= 1)
{
myString = "0000" + (String)fractionalpart;
}
else {
myString = "00000" + (String)fractionalpart;
}
myString.toCharArray(tempdata, 6);
*/
sprintf(tempdata, "%05d", fractionalpart); //This fails a large percentage of the time. When incorrect the value is always too low by 65537.
tempdata[5] = '\0'; //The terminator doesn't seem to matter in my application but it's something else I tried that didn't work.
char1 = tempdata[0] - '0';
char2 = tempdata[1] - '0';
char1 = char1 * 10 + char2;
gpsdata[x + 1] = char1; //first two numbers of fractional latitude
char1 = tempdata[2] - '0';
char2 = tempdata[3] - '0';
char1 = char1 * 10 + char2;
gpsdata[x + 2] = char1; //third and fouth numbers of fractional latitude
char1 = tempdata[4] - '0';
char1 = (char1 * 10) + signvalue;
gpsdata[x + 3] = char1; //fifth number and sign of latitude
}
void gpsdecompressor() {
gpsdecompress(0);
gpsdecompress(4);
}
void gpsdecompress(uint8_t x) {
uint8_t char1;
uint8_t char2;
uint8_t char3;
float tempcoordinate;
char tempdata[7]; //check length
char1 = gpsdata[x] - '0';
char1 += 48;
tempcoordinate = char1;
char1 = gpsdata[x + 1] - '0';
char2 = gpsdata[x + 2] - '0';
char3 = gpsdata[x + 3] - '0';
char1 += 48;
char2 += 48;
char3 += 48;
sprintf(tempdata, "%02d", char1);
sprintf(tempdata + 2, "%02d", char2);
sprintf(tempdata + 4, "%02d", char3);
tempdata[6] = '\0';
tempcoordinate = tempcoordinate + (float)atol(tempdata) / 1000000.0;
char1 = tempdata[5] - '0';
if (char1 == 1) {
tempcoordinate = -tempcoordinate;
}
if (x == 0) {
receivedlatitude = tempcoordinate;
}
else if (x == 4) {
receivedlongitude = tempcoordinate;
}
}