TinyGPS++ Crashes ESP32 (and probably others)

Code first, all necessary documentation at the bottom. This does not seem like the correct place but this is where the link took me to post questions/problems.

#include <TinyGPS++.h>

TinyGPSPlus gps;


void setup() {

  Serial.begin(115200);
  for (float fAngle = -180.; fAngle < 400.; fAngle++) {
    Serial.printf("fAngle = %.0f ", fAngle);
    Serial.printf("Cardinal %s\n", gps.cardinal(fAngle));
  }
}

void loop() {

//fAngle = -180 Cardinal 
//fAngle = -179 Cardinal 
//fAngle = -178 Cardinal 
//...  All OK, until....
//fAngle = -58 Cardinal 
//fAngle = -57 Cardinal 
//fAngle = -56 

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
//Core 1 register dump:
//PC      : 0x400014fd  PS      : 0x00060530  A0      : 0x800d8208  A1      : 0x3ffb1ae0  
//A2      : 0x00000000  A3      : 0xfffffffc  A4      : 0x000000ff  A5      : 0x0000ff00  
//A6      : 0x00ff0000  A7      : 0xff000000  A8      : 0x00000000  A9      : 0x3ffb1e20  
//A10     : 0x00000003  A11     : 0x00060123  A12     : 0x00060120  A13     : 0x00000020  
//A14     : 0x00000020  A15     : 0x00000000  SAR     : 0x0000001f  EXCCAUSE: 0x0000001c  
//EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff  
//
//Backtrace: 0x400014fd:0x3ffb1ae0 0x400d8205:0x3ffb1af0 0x400df736:0x3ffb1e00 0x400df76e:0x3ffb1e90 0x400d0ca8:0x3ffb1ed0 0x400d09ca:0x3ffb1f70 0x400e4047:0x3ffb1fa0
//
//Rebooting...
//ets Jun  8 2016 00:22:57
//
//rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
//configsip: 0, SPIWP:0xee
//clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
//mode:DIO, clock div:1
//load:0x3fff0018,len:4
//load:0x3fff001c,len:952
//load:0x40078000,len:6084
//load:0x40080000,len:7936
//entry 0x40080310
//fAngle = -180 Cardinal 
//...and so it goes, over and over.
}

The code has a bug. Following the cardinal() function (here):

const char *TinyGPSPlus::cardinal(double course)
{
  static const char* directions[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
  int direction = (int)((course + 11.25f) / 22.5f);
  return directions[direction % 16];
}

You see if it expects course to never be negative, because that would yield a negative direction and direction % 16 value. It computes direction % 16 to be a negative number, and thus you get something like directions[-7] returned, which is behind the start of the actual array:

#include <Arduino.h>

//Code from
//https://github.com/mikalhart/TinyGPSPlus/blob/master/src/TinyGPS%2B%2B.cpp#L330
const char *cardinal(double course) {
	static const char* directions[] = { "N", "NNE", "NE", "ENE", "E", "ESE",
			"SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW" };
	int direction = (int) ((course + 11.25f) / 22.5f);
	Serial.println("Chosen index: " + String(direction % 16));
	return directions[direction % 16];
}

void setup() {
	Serial.begin(115200);
	for (float fAngle = -180.; fAngle < 400.; fAngle++) {
		Serial.printf("fAngle = %.0f ", fAngle);
		Serial.printf("Cardinal %s\n", cardinal(fAngle));
	}
}

void loop() {
}

Outputs

fAngle = -180 Chosen index: -7
Cardinal 

The easy fix would be taking the angle modulo 360 and that it is always positive. An easy fix would be to add

	//is it negative?
	while(course < 0.0) {
		course += 360.0;
	}

or

	course = fmod(course, 360.0);
	if(course < 0.0)
		course += 360.0;

(with #include <math.h>)

at the start of the cardinal() function. Now it gives you

fAngle = -180 Chosen index: 8
Cardinal S

I.e. -180° is actually south now and it doesn’t crash.

1 Like