sparkfun / SparkFun_u-blox_GNSS_Arduino_Library

An Arduino library which allows you to communicate seamlessly with the full range of u-blox GNSS modules
Other
221 stars 100 forks source link

Issue with myGNSS.getVal8 #172

Closed PaulZC closed 1 year ago

PaulZC commented 1 year ago

Based on this forum post:

https://forum.sparkfun.com/viewtopic.php?p=237470#p237470

GNSS LIBRARY PROBLEM WITH MYGNSS.GETVAL8

I'm using the getVal8 library function to see whether the ZED-F9R is responding properly to my commands to turn on and off the sensor fusion. I'm getting variable results ---sometimes 0 and sometimes 1 for the RAM enable flag.

I think part of the problem may be that the function can return a zero value for two different issues: 1: It returns 0 when the flag is zero. That's the desired result. 2: It returns 0 when there is a communications error.

Here's the source code:

// Given a key, return its value
// This function takes a full 32-bit key
// Default layer is RAM
// Configuration of modern u-blox modules is now done via getVal/setVal/delVal, ie protocol v27 and above found on ZED-F9P
uint8_t SFE_UBLOX_GNSS::getVal8(uint32_t key, uint8_t layer, uint16_t maxWait)
{
  if (getVal(key, layer, maxWait) != SFE_UBLOX_STATUS_DATA_RECEIVED)
    return (0);

  return (extractByte(&packetCfg, 8));
}

I think there should be an error code returned that is not one-half the valid responses for the function return in cases where you are asking for the status of a logical flag that returns either 0 or 1.

PaulZC commented 1 year ago

Hello mborgerson,

Your point is completely valid. We try to keep the library functions (methods) as simple as possible. For most users, given the reliability of the u-blox interface, returning the value direct is the quickest and an acceptable solution. But, yes, a better way is to: return a success/fail error code; return the data via a pointer. In our more recent libraries, we have done exactly that: provide the pointer method, and also provide a simpler overload that returns the value direct.

The solution for you would be to call getVal directly and check the return value is SFE_UBLOX_STATUS_DATA_RECEIVED before extracting the data from packetCfg. Except packetCfg is private, so you cannot do that...

OK. To solve this properly, I do need to add pointer methods. However, we are already at the "tipping point" in terms of how much program memory this library uses. (See #169 for details.) So I'm reluctant to add the new methods...

We are working on a new version of the library where it will be much easier to add support for new messages, and to delete messages if required to save memory. But that won't be available for some time. (I suspect I will end up working on it over the Christmas holiday!)

Instead, you could use a custom packet to read the value. Please see examples 20 and 21 for details.

In your case, the code would be:

  // Create a custom packet
  uint8_t customPayload[9]; // This array holds the key during the poll request, and the returned key plus value from the GETVAL

  // The next line creates and initialises the packet information which wraps around the payload
  ubxPacket customCfg = {0, 0, 0, 0, 0, customPayload, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED};

  customCfg.cls = UBX_CLASS_CFG; // This is the message Class
  customCfg.id = UBX_CFG_VALGET; // This is the message ID
  customCfg.len = 8; // Setting the len (length) to 8 let's us poll a single key
  customCfg.startingSpot = 0; // Always set the startingSpot to zero (unless you really know what you are doing)

  uint32_t key = UBLOX_CFG_MSGOUT_UBX_ESF_STATUS_I2C; // Set this to the key you want to read

  customPayload[0] = 0; // Message version
  customPayload[1] = 0; // 0 = RAM Layer; 7 = Default layer
  customPayload[2] = 0; // Position - skip this many keys
  customPayload[3] = 0; // Position - skip this many keys
  customPayload[4] = (key >> 8 * 0) & 0xFF; // Key LSB
  customPayload[5] = (key >> 8 * 1) & 0xFF;
  customPayload[6] = (key >> 8 * 2) & 0xFF;
  customPayload[7] = (key >> 8 * 3) & 0xFF;

  // We also need to tell sendCommand how long it should wait for a reply
  uint16_t maxWait = 250; // Wait for up to 250ms (Serial may need a lot longer e.g. 1100)

  if (myGNSS.sendCommand(&customCfg, maxWait) == SFE_UBLOX_STATUS_DATA_RECEIVED) // We are expecting data and an ACK
  {
    uint8_t keyValue = customPayload[8]; // Extract the 8-bit data following the key 
    Serial.println(keyValue);
  }

I've tested the above on a ZED-F9R and it works. But I don't know which key you are trying to read. Please adapt the code as necessary.

Apologies for the inconvenience, but this is at least a workable solution for you. Please let me know if it works for you.

Best wishes, Paul

PaulZC commented 1 year ago

Just a note that this has been resolved in v3 of the library.

v3 contains 'safe' versions of getVal - using pointers to return the value - as well as overloads for the original 'unsafe' versions.

PaulZC commented 1 year ago

This is resolved in v3 of the library:

https://github.com/sparkfun/SparkFun_u-blox_GNSS_v3

It is still Work-In-Progress. I'm slowly working my way through the examples, updating and testing each one as I go. But I'm confident the library is useable as-is.

You won't be able to install it via the Arduino Library Manager. For now, you will need to download it and install it manually.

PaulZC commented 1 year ago

https://github.com/sparkfun/SparkFun_u-blox_GNSS_v3/blob/main/src/u-blox_GNSS.h#L427-L434

Closing...