Best Practice - Decoder 12500

Hi BeeGee,

We are working with the GPS best practice example.

https://github.com/RAKWireless/RUI3-Best-Practice/tree/main/RUI3-RAK12500-RAK1904-GNSS

decoder:

https://github.com/RAKWireless/RAKwireless_Standardized_Payload/blob/main/RAKwireless_Standardized_Payload.js

The decoder mentioned in the usage was used but we have problems decoding the payload.

The location is correct in the console but the longitude decoder does not do it correctly.

image

I performed the manual decoding and from what I have analyzed it seems that the data sent by is not correct, since the decoding is correct

image

Can you guide me in case I am doing something wrong please.

best regards

Are you using the latest version? I fixed 2 months ago a bug with lat/long where the values were unsigned integers instead of signed integers (which is the correct usage).

The corrected functions are
uint8_t WisCayenne::addGNSS_4(uint8_t channel, int32_t latitude, int32_t longitude, int32_t altitude)
uint8_t WisCayenne::addGNSS_6(uint8_t channel, int32_t latitude, int32_t longitude, int32_t altitude)

You should use the latest wisblock_cayenne.cpp and wisblock_cayenne.h

1 Like

Hi beegge,

I’ve been working with your example and I’ve tried to add the time in unixtime to payload but I haven’t had any luck.

I made changes to wisblock_cayenne.cpp and wisblock_cayenne.h but it didn’t work for me

uint8_t WisCayenne::addGNSS_6(uint8_t channel, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t unixtime, uint16_t speed)
{
    // check buffer overflow
    if ((_cursor + LPP_GPS6_SIZE + 2 + 6) > _maxsize) // +6 para unixtime (4 bytes) y speed (2 bytes)
    {
        _error = LPP_ERROR_OVERFLOW;
        return 0;
    }

    // Agregar latitud, longitud y altitud (ya explicado anteriormente)
    _buffer[_cursor++] = channel;
    _buffer[_cursor++] = LPP_GPS6;

    latLong_s pos_union;

    // Latitud
    pos_union.val32 = latitude / 10; // Custom 0.000001 ° Signed MSB
    _buffer[_cursor++] = pos_union.val8[3];
    _buffer[_cursor++] = pos_union.val8[2];
    _buffer[_cursor++] = pos_union.val8[1];
    _buffer[_cursor++] = pos_union.val8[0];

    // Longitud
    pos_union.val32 = longitude / 10; // Custom 0.000001 ° Signed MSB
    _buffer[_cursor++] = pos_union.val8[3];
    _buffer[_cursor++] = pos_union.val8[2];
    _buffer[_cursor++] = pos_union.val8[1];
    _buffer[_cursor++] = pos_union.val8[0];

    // Altitud
    pos_union.val32 = altitude / 10; // Cayenne LPP 0.01 meter Signed MSB
    _buffer[_cursor++] = pos_union.val8[2];
    _buffer[_cursor++] = pos_union.val8[1];
    _buffer[_cursor++] = pos_union.val8[0];

    // Agregar unixtime (en formato entero de 32 bits, canal 102)
    _buffer[_cursor++] = 102;             // Canal para unixtime
    _buffer[_cursor++] = LPP_UNIXTIME2;    // Tipo de dato personalizado para unixtime
    pos_union.val32 = unixtime;
    _buffer[_cursor++] = pos_union.val8[3];
    _buffer[_cursor++] = pos_union.val8[2];
    _buffer[_cursor++] = pos_union.val8[1];
    _buffer[_cursor++] = pos_union.val8[0];

    // Agregar speed (en formato entero de 16 bits, canal 103)
    _buffer[_cursor++] = 103;             // Canal para speed
    _buffer[_cursor++] = LPP_SPEED;       // Tipo de dato personalizado para speed
    pos_union.val32 = speed;        // Multiplicar por 100 para mantener dos decimales (0.01 m/s)
    _buffer[_cursor++] = pos_union.val8[1];
    _buffer[_cursor++] = pos_union.val8[0];

    return _cursor;
}
uint8_t addGNSS_6(uint8_t channel, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t unixtime, uint16_t speed);

Afterwards I decided to leave it as it was at the beginning and modified only RAK12500_gss.cpp

/**
 * @file RAK12500_gnss.cpp
 * @author Bernd Giesecke ([email protected])
 * @brief Initialization and usage of RAK12500
 * @version 0.1
 * @date 2024-01-14
 *
 * @copyright Copyright (c) 2024
 *
 */
#include "../inc/app.h"
#include <SparkFun_u-blox_GNSS_Arduino_Library.h>

/** Instance for RAK12500 GNSS sensor */
SFE_UBLOX_GNSS my_gnss;

// GNSS functions
#define NO_GNSS_INIT 0
#define RAK1910_GNSS 1
#define RAK12500_GNSS 2

// Fake GPS Enable (1) Disable (0)
#define FAKE_GPS 0

/** GNSS polling function */
bool poll_gnss(void);

/** Flag if location was found */
volatile bool last_read_ok = false;

/** Flag if GNSS is serial or I2C */
bool i2c_gnss = false;

/** The GPS module to use */
uint8_t g_gnss_option = 2;

/** Start time of location acquisition */
time_t gnss_start;
/** End time of location acquisition */
time_t gnss_finished;

/**
 * @brief Initialize GNSS module
 *
 * @return true if GNSS module was found
 * @return false if no GNSS module was found
 */
bool init_gnss(void)
{
	// Power on the GNSS module
	digitalWrite(WB_IO2, HIGH);

	// Give the module some time to power up
	delay(500);

	if (!my_gnss.begin(Wire))
	{
		MYLOG("GNSS", "Could not initialize RAK12500 on Wire");
		return false;
	}
	my_gnss.setI2COutput(COM_TYPE_UBX); // Set the I2C port to output UBX only (turn off NMEA noise)

	my_gnss.saveConfiguration(); // Save the current settings to flash and BBR

	my_gnss.setMeasurementRate(500);

	return true;
}

/**
 * @brief GNSS location acquisition
 * Called every 2.5 seconds by timer 1
 * Gives up after 1/2 of send interval
 * or when location was aquired
 *
 */
void gnss_handler(void *)
{
	digitalWrite(LED_GREEN, HIGH);
	if (poll_gnss())
	{
		// Power down the module
		digitalWrite(WB_IO2, LOW);
		delay(100);
		MYLOG("GNSS", "Got location");
		api.system.timer.stop(RAK_TIMER_1);
		gnss_finished = millis();
		digitalWrite(LED_BLUE, HIGH);
		send_packet();
	}
	else
	{
		if (check_gnss_counter >= check_gnss_max_try)
		{
			// Power down the module
			digitalWrite(WB_IO2, LOW);
			delay(100);
			MYLOG("GNSS", "Location timeout");
			api.system.timer.stop(RAK_TIMER_1);
			gnss_finished = millis();
			digitalWrite(LED_BLUE, HIGH);
			send_packet();
		}
	}
	check_gnss_counter++;
	digitalWrite(LED_GREEN, LOW);
}

/**
 * @brief Check GNSS module for position
 *
 * @return true Valid position found
 * @return false No valid position
 */
bool poll_gnss(void)
{
	last_read_ok = false;

	time_t time_out = millis();
	int64_t latitude = 0;
	int64_t longitude = 0;
	int32_t altitude = 0;
	int16_t accuracy = 0;
	uint8_t satellites = 0;
	float speed = 0;
	time_t unix_time = 0;

	// Obtener fecha y hora
	uint16_t year = 0;
	uint8_t month = 0;
	uint8_t day = 0;
	uint8_t hour = 0;
	uint8_t minute = 0;
	uint8_t second = 0;

	bool has_pos = false;
	bool has_alt = false;

	if (my_gnss.getGnssFixOk())
	{
		byte fix_type = my_gnss.getFixType(); // Get the fix type
		char fix_type_str[32] = {0};
#if MY_DEBUG > 0
		if (fix_type == 0)
			sprintf(fix_type_str, "No Fix");
		else if (fix_type == 1)
			sprintf(fix_type_str, "Dead reckoning");
		else if (fix_type == 2)
			sprintf(fix_type_str, "Fix type 2D");
		else if (fix_type == 3)
			sprintf(fix_type_str, "Fix type 3D");
		else if (fix_type == 4)
			sprintf(fix_type_str, "GNSS fix");
		else if (fix_type == 5)
			sprintf(fix_type_str, "Time fix");
#endif
		if ((fix_type >= 3) && (my_gnss.getSIV() >= 5)) /** Fix type 3D and at least 5 satellites */
														// if (fix_type >= 3) /** Fix type 3D */
		{
			last_read_ok = true;
			latitude = my_gnss.getLatitude();
			longitude = my_gnss.getLongitude();
			altitude = my_gnss.getAltitude();
			accuracy = my_gnss.getHorizontalDOP();
			satellites = my_gnss.getSIV();
			speed = my_gnss.getGroundSpeed();
			
			// Obtener fecha y hora
			year = my_gnss.getYear();
			month = my_gnss.getMonth();
			day = my_gnss.getDay();
			hour = my_gnss.getHour();
			minute = my_gnss.getMinute();
			second = my_gnss.getSecond();

			// Crear estructura tm para la fecha y hora
			struct tm timeinfo;
			timeinfo.tm_year = year - 1900;  // El año en la estructura tm se cuenta desde 1900
			timeinfo.tm_mon = month - 1;     // Los meses en tm van de 0 a 11
			timeinfo.tm_mday = day;
			timeinfo.tm_hour = hour;
			timeinfo.tm_min = minute;
			timeinfo.tm_sec = second;
			timeinfo.tm_isdst = 0;  // Sin horario de verano

			// Convertir a Unix timestamp
			time_t unix_time = mktime(&timeinfo);

	
			// Verificar si hubo un error en la conversión
			if (unix_time == -1) {
    		MYLOG("GNSS", "Error en la conversión a Unix Timestamp");
   			return false;
			}


			MYLOG("GNSS", "Fixtype: %d %s", my_gnss.getFixType(), fix_type_str);
			MYLOG("GNSS", "Lat: %.4f Lon: %.4f", latitude / 10000000.0, longitude / 10000000.0);
			MYLOG("GNSS", "Alt: %.2f", altitude / 1000.0);
			MYLOG("GNSS", "Acy: %.2f ", accuracy / 100.0);
			MYLOG("GNSS", "Sat: %d", satellites); 
			MYLOG("GNSS", "Spe: %.2f km/h", speed * 0.0036); // Convertir a km/h

			// Log de fecha y hora UTC
			MYLOG("GNSS", "Fecha: %04d-%02d-%02d", year, month, day);
			MYLOG("GNSS", "Hora UTC: %02d:%02d:%02d", hour, minute, second);
			MYLOG("GNSS", "Unix Timestamp: %ld",(long) unix_time);  // Mostrar el Unix timestamp


		}
	}

	char disp_str[255];
	if (last_read_ok)
	{
		if ((latitude == 0) && (longitude == 0))
		{
			last_read_ok = false;
			return false;
		}

		// Add the location to the payload
		g_solution_data.addGNSS_6(LPP_CHANNEL_GPS, latitude, longitude, altitude);
		g_solution_data.addGenericSensor(LPP_CHANNEL_SPEED, speed);
		g_solution_data.addUnixTime(LPP_CHANNEL_UNIXTIME, unix_time);

		return true;
	}
	else
	{
		// No location found
#if FAKE_GPS > 0
		MYLOG("GNSS", "Faking GPS");
		// 14.4213730, 121.0069140, 35.000
		latitude = 144213730;
		longitude = 1210069140;
		altitude = 35000;
		accuracy = 1;
		satellites = 18;

		g_solution_data.addGNSS_6(LPP_CHANNEL_GPS, latitude, longitude, altitude);
		last_read_ok = true;
		return true;
#endif
	}

	// MYLOG("GNSS", "No valid location found");
	last_read_ok = false;
	return false;
}

The result is always 0000000 for unixtime but for speed it is working without any problem.

017401870a89008a1e9cfb44149f001b631464000000071e85000000000a8500000015
11:21:02:959 -> [GNSS] Lat: 9.0518 Lon: -79.4244
11:21:03:059 -> [GNSS] Alt: 37.43
11:21:03:159 -> [GNSS] Acy: 2.03 
11:21:03:259 -> [GNSS] Sat: 9
11:21:03:359 -> [GNSS] Spe: 0.12 km/h
11:21:03:459 -> [GNSS] Fecha: 2024-09-22
11:21:03:559 -> [GNSS] Hora UTC: 16:21:03
11:21:03:659 -> [GNSS] Unix Timestamp: 1727022063
	
     Bat	    Lat	     Lon	 Alt	Speed mm/s   unix timestamp  Unix time start - finish 
0174 0186 0a89 008a1ea8 fb44144e 000e9f 146400000020 1e85 00000000   0a85 00000019

Can you tell me what would be the best way to get this data or if you can verify that I’m doing it wrong?

Best Regards.,

My code is not waiting for a time fix, it might be the GNSS receiver doesn’t have the time yet.

As you can see in the code, Time Fix is fix_type 5. But the if() is only checking for fix_type >4.
You might change that line to

if ((fix_type >= 5) && (my_gnss.getSIV() >= 5))

to be sure the RAK12500 has actually a time.

Hello,

I forgot to attach a photo of the console. I can confirm that I am receiving the correct time data in Unix, but the problem is that it does not add it to the payload.

image

With the current configuration:

if ((fix_type >= 3) && (my_gnss.getSIV() >= 5))

Or it is not converting to hexadecimal, I have some error.

You are defining time_t unix_time twice in your code.Once in the beginning of bool poll_gnss(void) and a second time when you convert the time_info structure to UNIX time.

When you add the unix_time to the payload later, it will use the first one (I guess).

image

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.