From 850cce0ec70e2b86ef22cf6e35a634816d81097e Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 22 Dec 2019 16:59:11 +0000 Subject: [PATCH 1/5] Added powerSaveMode (and some minor corrections) --- .../Example19_PowerSaveMode.ino | 123 ++++++++++ keywords.txt | 2 + src/SparkFun_Ublox_Arduino_Library.cpp | 223 +++++++++++------- src/SparkFun_Ublox_Arduino_Library.h | 28 ++- 4 files changed, 278 insertions(+), 98 deletions(-) create mode 100644 examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino diff --git a/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino b/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino new file mode 100644 index 0000000..7cb05aa --- /dev/null +++ b/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino @@ -0,0 +1,123 @@ +/* + Power Save Mode + By: Paul Clark (PaulZC) + Date: December 18th, 2019 + + Based extensively on Example3_GetPosition + By: Nathan Seidle + SparkFun Electronics + Date: January 3rd, 2019 + License: MIT. See license file for more information but you can + basically do whatever you want with this code. + + This example shows how to put the Ublox module into power save mode and then + query its lat/long/altitude. We also turn off the NMEA output on the I2C port. + This decreases the amount of I2C traffic dramatically. + + ** When it is able to ** the module will reduce its current draw. + For the ZOE-M8Q with a passive antenna, you should see the current drop + from (approx.) 25-28mA to (approx.) 9mA when power save mode kicks in. + + Note: this will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported + + Note: Long/lat are large numbers because they are * 10^7. To convert lat/long + to something google maps understands simply divide the numbers by 10,000,000. We + do this so that we don't have to use floating point numbers. + + Leave NMEA parsing behind. Now you can simply ask the module for the datums you want! + + Feel like supporting open source hardware? + Buy a board from SparkFun! + ZED-F9P RTK2: https://www.sparkfun.com/products/15136 + NEO-M8P RTK: https://www.sparkfun.com/products/15005 + SAM-M8Q: https://www.sparkfun.com/products/15106 + + Hardware Connections: + Plug a Qwiic cable into the GPS and a BlackBoard + If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425) + Open the serial monitor at 115200 baud to see the output +*/ + +#include //Needed for I2C to GPS + +#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module. + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println("SparkFun Ublox Example"); + + Wire.begin(); + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + + //myGPS.enableDebugging(); // Uncomment this line to enable debug messages + + Serial.println(F("Waiting for a 3D fix...")); + + byte fixType = 0; + + while (fixType != 3) // Wait for a 3D fix + { + fixType = myGPS.getFixType(); // Get the fix type + Serial.print(F("Fix: ")); + Serial.print(fixType); + if(fixType == 0) Serial.print(F(" = No fix")); + else if(fixType == 1) Serial.print(F(" = Dead reckoning")); + else if(fixType == 2) Serial.print(F(" = 2D")); + else if(fixType == 3) Serial.print(F(" = 3D")); + else if(fixType == 4) Serial.print(F(" = GNSS + Dead reckoning")); + Serial.println(); + delay(1000); + } + + Serial.println(F("3D fix found! Engaging power save mode...")); + + // Put the GNSS into power save mode + // (If you want to disable power save mode, call myGPS.powerSaveMode(false) instead) + // This will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported + if (myGPS.powerSaveMode()) + { + Serial.println(F("Power Save Mode enabled.")); + } + else + { + Serial.println(F("***!!! Power Save Mode FAILED !!!***")); + } + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + //myGPS.saveConfiguration(); //Uncomment this line to save the current settings to flash and BBR +} + +void loop() +{ + //Query module every 10 seconds so it is easier to monitor the current draw + if (millis() - lastTime > 10000) + { + lastTime = millis(); //Update the timer + + long latitude = myGPS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGPS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGPS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + Serial.println(); + } +} diff --git a/keywords.txt b/keywords.txt index f0d1ed7..ec9899c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -125,6 +125,8 @@ addGeofence KEYWORD2 clearGeofences KEYWORD2 getGeofenceState KEYWORD2 +powerSaveMode KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 5fc9e9d..f48700d 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -1642,89 +1642,89 @@ boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, boolean implicitUpdate, uint16 //Add a new geofence using UBX-CFG-GEOFENCE boolean SFE_UBLOX_GPS::addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, byte confidence, byte pinPolarity, byte pin, uint16_t maxWait) { - if (currentGeofenceParams.numFences >= 4) return(false); // Quit if we already have four geofences defined - - // Store the new geofence parameters - currentGeofenceParams.lats[currentGeofenceParams.numFences] = latitude; - currentGeofenceParams.longs[currentGeofenceParams.numFences] = longitude; - currentGeofenceParams.rads[currentGeofenceParams.numFences] = radius; - currentGeofenceParams.numFences = currentGeofenceParams.numFences + 1; // Increment the number of fences - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_GEOFENCE; - packetCfg.len = (currentGeofenceParams.numFences * 12) + 8; - packetCfg.startingSpot = 0; - - payloadCfg[0] = 0; // Message version = 0x00 - payloadCfg[1] = currentGeofenceParams.numFences; // numFences - payloadCfg[2] = confidence; // confLvl = Confidence level 0-4 (none, 68%, 95%, 99.7%, 99.99%) - payloadCfg[3] = 0; // reserved1 - if (pin > 0) - { - payloadCfg[4] = 1; // enable PIO combined fence state - } - else - { - payloadCfg[4] = 0; // disable PIO combined fence state - } - payloadCfg[5] = pinPolarity; // PIO pin polarity (0 = low means inside, 1 = low means outside (or unknown)) - payloadCfg[6] = pin; // PIO pin - payloadCfg[7] = 0; //reserved2 - payloadCfg[8] = currentGeofenceParams.lats[0] & 0xFF; - payloadCfg[9] = currentGeofenceParams.lats[0] >> 8; - payloadCfg[10] = currentGeofenceParams.lats[0] >> 16; - payloadCfg[11] = currentGeofenceParams.lats[0] >> 24; - payloadCfg[12] = currentGeofenceParams.longs[0] & 0xFF; - payloadCfg[13] = currentGeofenceParams.longs[0] >> 8; - payloadCfg[14] = currentGeofenceParams.longs[0] >> 16; - payloadCfg[15] = currentGeofenceParams.longs[0] >> 24; - payloadCfg[16] = currentGeofenceParams.rads[0] & 0xFF; - payloadCfg[17] = currentGeofenceParams.rads[0] >> 8; - payloadCfg[18] = currentGeofenceParams.rads[0] >> 16; - payloadCfg[19] = currentGeofenceParams.rads[0] >> 24; - if (currentGeofenceParams.numFences >= 2) { - payloadCfg[20] = currentGeofenceParams.lats[1] & 0xFF; - payloadCfg[21] = currentGeofenceParams.lats[1] >> 8; - payloadCfg[22] = currentGeofenceParams.lats[1] >> 16; - payloadCfg[23] = currentGeofenceParams.lats[1] >> 24; - payloadCfg[24] = currentGeofenceParams.longs[1] & 0xFF; - payloadCfg[25] = currentGeofenceParams.longs[1] >> 8; - payloadCfg[26] = currentGeofenceParams.longs[1] >> 16; - payloadCfg[27] = currentGeofenceParams.longs[1] >> 24; - payloadCfg[28] = currentGeofenceParams.rads[1] & 0xFF; - payloadCfg[29] = currentGeofenceParams.rads[1] >> 8; - payloadCfg[30] = currentGeofenceParams.rads[1] >> 16; - payloadCfg[31] = currentGeofenceParams.rads[1] >> 24; - } - if (currentGeofenceParams.numFences >= 3) { - payloadCfg[32] = currentGeofenceParams.lats[2] & 0xFF; - payloadCfg[33] = currentGeofenceParams.lats[2] >> 8; - payloadCfg[34] = currentGeofenceParams.lats[2] >> 16; - payloadCfg[35] = currentGeofenceParams.lats[2] >> 24; - payloadCfg[36] = currentGeofenceParams.longs[2] & 0xFF; - payloadCfg[37] = currentGeofenceParams.longs[2] >> 8; - payloadCfg[38] = currentGeofenceParams.longs[2] >> 16; - payloadCfg[39] = currentGeofenceParams.longs[2] >> 24; - payloadCfg[40] = currentGeofenceParams.rads[2] & 0xFF; - payloadCfg[41] = currentGeofenceParams.rads[2] >> 8; - payloadCfg[42] = currentGeofenceParams.rads[2] >> 16; - payloadCfg[43] = currentGeofenceParams.rads[2] >> 24; - } - if (currentGeofenceParams.numFences >= 4) { - payloadCfg[44] = currentGeofenceParams.lats[3] & 0xFF; - payloadCfg[45] = currentGeofenceParams.lats[3] >> 8; - payloadCfg[46] = currentGeofenceParams.lats[3] >> 16; - payloadCfg[47] = currentGeofenceParams.lats[3] >> 24; - payloadCfg[48] = currentGeofenceParams.longs[3] & 0xFF; - payloadCfg[49] = currentGeofenceParams.longs[3] >> 8; - payloadCfg[50] = currentGeofenceParams.longs[3] >> 16; - payloadCfg[51] = currentGeofenceParams.longs[3] >> 24; - payloadCfg[52] = currentGeofenceParams.rads[3] & 0xFF; - payloadCfg[53] = currentGeofenceParams.rads[3] >> 8; - payloadCfg[54] = currentGeofenceParams.rads[3] >> 16; - payloadCfg[55] = currentGeofenceParams.rads[3] >> 24; - } - return (sendCommand(packetCfg, maxWait)); //Wait for ack + if (currentGeofenceParams.numFences >= 4) return(false); // Quit if we already have four geofences defined + + // Store the new geofence parameters + currentGeofenceParams.lats[currentGeofenceParams.numFences] = latitude; + currentGeofenceParams.longs[currentGeofenceParams.numFences] = longitude; + currentGeofenceParams.rads[currentGeofenceParams.numFences] = radius; + currentGeofenceParams.numFences = currentGeofenceParams.numFences + 1; // Increment the number of fences + + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_GEOFENCE; + packetCfg.len = (currentGeofenceParams.numFences * 12) + 8; + packetCfg.startingSpot = 0; + + payloadCfg[0] = 0; // Message version = 0x00 + payloadCfg[1] = currentGeofenceParams.numFences; // numFences + payloadCfg[2] = confidence; // confLvl = Confidence level 0-4 (none, 68%, 95%, 99.7%, 99.99%) + payloadCfg[3] = 0; // reserved1 + if (pin > 0) + { + payloadCfg[4] = 1; // enable PIO combined fence state + } + else + { + payloadCfg[4] = 0; // disable PIO combined fence state + } + payloadCfg[5] = pinPolarity; // PIO pin polarity (0 = low means inside, 1 = low means outside (or unknown)) + payloadCfg[6] = pin; // PIO pin + payloadCfg[7] = 0; //reserved2 + payloadCfg[8] = currentGeofenceParams.lats[0] & 0xFF; + payloadCfg[9] = currentGeofenceParams.lats[0] >> 8; + payloadCfg[10] = currentGeofenceParams.lats[0] >> 16; + payloadCfg[11] = currentGeofenceParams.lats[0] >> 24; + payloadCfg[12] = currentGeofenceParams.longs[0] & 0xFF; + payloadCfg[13] = currentGeofenceParams.longs[0] >> 8; + payloadCfg[14] = currentGeofenceParams.longs[0] >> 16; + payloadCfg[15] = currentGeofenceParams.longs[0] >> 24; + payloadCfg[16] = currentGeofenceParams.rads[0] & 0xFF; + payloadCfg[17] = currentGeofenceParams.rads[0] >> 8; + payloadCfg[18] = currentGeofenceParams.rads[0] >> 16; + payloadCfg[19] = currentGeofenceParams.rads[0] >> 24; + if (currentGeofenceParams.numFences >= 2) { + payloadCfg[20] = currentGeofenceParams.lats[1] & 0xFF; + payloadCfg[21] = currentGeofenceParams.lats[1] >> 8; + payloadCfg[22] = currentGeofenceParams.lats[1] >> 16; + payloadCfg[23] = currentGeofenceParams.lats[1] >> 24; + payloadCfg[24] = currentGeofenceParams.longs[1] & 0xFF; + payloadCfg[25] = currentGeofenceParams.longs[1] >> 8; + payloadCfg[26] = currentGeofenceParams.longs[1] >> 16; + payloadCfg[27] = currentGeofenceParams.longs[1] >> 24; + payloadCfg[28] = currentGeofenceParams.rads[1] & 0xFF; + payloadCfg[29] = currentGeofenceParams.rads[1] >> 8; + payloadCfg[30] = currentGeofenceParams.rads[1] >> 16; + payloadCfg[31] = currentGeofenceParams.rads[1] >> 24; + } + if (currentGeofenceParams.numFences >= 3) { + payloadCfg[32] = currentGeofenceParams.lats[2] & 0xFF; + payloadCfg[33] = currentGeofenceParams.lats[2] >> 8; + payloadCfg[34] = currentGeofenceParams.lats[2] >> 16; + payloadCfg[35] = currentGeofenceParams.lats[2] >> 24; + payloadCfg[36] = currentGeofenceParams.longs[2] & 0xFF; + payloadCfg[37] = currentGeofenceParams.longs[2] >> 8; + payloadCfg[38] = currentGeofenceParams.longs[2] >> 16; + payloadCfg[39] = currentGeofenceParams.longs[2] >> 24; + payloadCfg[40] = currentGeofenceParams.rads[2] & 0xFF; + payloadCfg[41] = currentGeofenceParams.rads[2] >> 8; + payloadCfg[42] = currentGeofenceParams.rads[2] >> 16; + payloadCfg[43] = currentGeofenceParams.rads[2] >> 24; + } + if (currentGeofenceParams.numFences >= 4) { + payloadCfg[44] = currentGeofenceParams.lats[3] & 0xFF; + payloadCfg[45] = currentGeofenceParams.lats[3] >> 8; + payloadCfg[46] = currentGeofenceParams.lats[3] >> 16; + payloadCfg[47] = currentGeofenceParams.lats[3] >> 24; + payloadCfg[48] = currentGeofenceParams.longs[3] & 0xFF; + payloadCfg[49] = currentGeofenceParams.longs[3] >> 8; + payloadCfg[50] = currentGeofenceParams.longs[3] >> 16; + payloadCfg[51] = currentGeofenceParams.longs[3] >> 24; + payloadCfg[52] = currentGeofenceParams.rads[3] & 0xFF; + payloadCfg[53] = currentGeofenceParams.rads[3] >> 8; + payloadCfg[54] = currentGeofenceParams.rads[3] >> 16; + payloadCfg[55] = currentGeofenceParams.rads[3] >> 24; + } + return (sendCommand(packetCfg, maxWait)); //Wait for ack } //Clear all geofences using UBX-CFG-GEOFENCE @@ -1789,6 +1789,53 @@ boolean SFE_UBLOX_GPS::getGeofenceState(geofenceState ¤tGeofenceState, uin return(true); } +//Power Save Mode +//Enables/Disables Low Power Mode using UBX-CFG-RXM +boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) +{ + // Let's begin by checking the Protocol Version as UBX_CFG_RXM is not supported on the ZED (protocol >= 27) + uint8_t protVer = getProtocolVersionHigh(); + /* + if (_printDebug == true) + { + _debugSerial->print("Protocol version is "); + _debugSerial->println(protVer); + } + */ + if (protVer >= 27) + { + debugPrintln((char *)"powerSaveMode (UBX-CFG-RXM) is not supported by this protocol version"); + return (false); + } + + // Now let's change the power setting using UBX-CFG-RXM + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_RXM; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(packetCfg, maxWait) == false) //Ask module for the current power management settings. Loads into payloadCfg. + return (false); + + // Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response) + // This is only required because we are doing two sendCommands in quick succession using the same class and ID + waitForResponse(UBX_CLASS_CFG, UBX_CFG_RXM, 100); // But we'll only wait for 100msec max + + if (power_save) + { + payloadCfg[1] = 1; // Power Save Mode + } + else + { + payloadCfg[1] = 0; // Continuous Mode + } + + packetCfg.len = 2; + packetCfg.startingSpot = 0; + + return (sendCommand(packetCfg, maxWait)); //Wait for ack +} + //Given a spot in the payload array, extract four bytes and build a long uint32_t SFE_UBLOX_GPS::extractLong(uint8_t spotToStart) { @@ -2133,7 +2180,7 @@ uint16_t SFE_UBLOX_GPS::getPDOP(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getProtocolVersionHigh(uint16_t maxWait) { if (moduleQueried.versionNumber == false) - getProtocolVersion(); + getProtocolVersion(maxWait); moduleQueried.versionNumber = false; return (versionHigh); } @@ -2143,7 +2190,7 @@ uint8_t SFE_UBLOX_GPS::getProtocolVersionHigh(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getProtocolVersionLow(uint16_t maxWait) { if (moduleQueried.versionNumber == false) - getProtocolVersion(); + getProtocolVersion(maxWait); moduleQueried.versionNumber = false; return (versionLow); } @@ -2166,6 +2213,10 @@ boolean SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait) if (sendCommand(packetCfg, maxWait) == false) return (false); //If command send fails then bail + // Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response) + // This is only required because we are doing multiple sendCommands in quick succession using the same class and ID + waitForResponse(UBX_CLASS_MON, UBX_MON_VER, 100); // But we'll only wait for 100msec max + if (_printDebug == true) { _debugSerial->print("Extension "); @@ -2185,7 +2236,7 @@ boolean SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait) { versionHigh = (payloadCfg[8] - '0') * 10 + (payloadCfg[9] - '0'); //Convert '18' to 18 versionLow = (payloadCfg[11] - '0') * 10 + (payloadCfg[12] - '0'); //Convert '00' to 00 - return (versionLow); + return (true); // This function returns a boolean (so we can't return versionLow) } } diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index 9d3c409..efb3c5d 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -99,6 +99,7 @@ const uint8_t UBX_CFG_PRT = 0x00; //Used to configure port specifics const uint8_t UBX_CFG_RST = 0x04; //Used to reset device const uint8_t UBX_CFG_RATE = 0x08; //Used to set port baud rates const uint8_t UBX_CFG_CFG = 0x09; //Used to save current configuration +const uint8_t UBX_CFG_RXM = 0x11; //Used to set receiver power management (power save mode) const uint8_t UBX_CFG_VALSET = 0x8A; //Used for config of higher version Ublox modules (ie protocol v27 and above) const uint8_t UBX_CFG_VALGET = 0x8B; //Used for config of higher version Ublox modules (ie protocol v27 and above) const uint8_t UBX_CFG_VALDEL = 0x8C; //Used for config of higher version Ublox modules (ie protocol v27 and above) @@ -195,18 +196,18 @@ typedef struct // Struct to hold the results returned by getGeofenceState (returned by UBX-NAV-GEOFENCE) typedef struct { - uint8_t status; // Geofencing status: 0 - Geofencing not available or not reliable; 1 - Geofencing active - uint8_t numFences; // Number of geofences - uint8_t combState; // Combined (logical OR) state of all geofences: 0 - Unknown; 1 - Inside; 2 - Outside - uint8_t states[4]; // Geofence states: 0 - Unknown; 1 - Inside; 2 - Outside + uint8_t status; // Geofencing status: 0 - Geofencing not available or not reliable; 1 - Geofencing active + uint8_t numFences; // Number of geofences + uint8_t combState; // Combined (logical OR) state of all geofences: 0 - Unknown; 1 - Inside; 2 - Outside + uint8_t states[4]; // Geofence states: 0 - Unknown; 1 - Inside; 2 - Outside } geofenceState; // Struct to hold the current geofence parameters typedef struct { - uint8_t numFences; // Number of active geofences - int32_t lats[4]; // Latitudes of geofences (in degrees * 10^-7) - int32_t longs[4]; // Longitudes of geofences (in degrees * 10^-7) - uint32_t rads[4]; // Radii of geofences (in m * 10^-2) + uint8_t numFences; // Number of active geofences + int32_t lats[4]; // Latitudes of geofences (in degrees * 10^-7) + int32_t longs[4]; // Longitudes of geofences (in degrees * 10^-7) + uint32_t rads[4]; // Radii of geofences (in m * 10^-2) } geofenceParams; class SFE_UBLOX_GPS @@ -339,10 +340,13 @@ class SFE_UBLOX_GPS void debugPrint(char *message); //Safely print debug statements void debugPrintln(char *message); //Safely print debug statements - //Support for geofences - boolean addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, byte confidence = 0, byte pinPolarity = 0, byte pin = 0, uint16_t maxWait = 2000); // Add a new geofence - boolean clearGeofences(uint16_t maxWait = 2000); //Clears all geofences - boolean getGeofenceState(geofenceState ¤tGeofenceState, uint16_t maxWait = 2000); //Returns the combined geofence state + //Support for geofences + boolean addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, byte confidence = 0, byte pinPolarity = 0, byte pin = 0, uint16_t maxWait = 2000); // Add a new geofence + boolean clearGeofences(uint16_t maxWait = 2000); //Clears all geofences + boolean getGeofenceState(geofenceState ¤tGeofenceState, uint16_t maxWait = 2000); //Returns the combined geofence state + + //Power Save Mode + boolean powerSaveMode(bool power_save = true, uint16_t maxWait = 2000); //Survey-in specific controls struct svinStructure From ead94de53455593b119f73aeba24f0077a79953f Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 22 Dec 2019 17:12:08 +0000 Subject: [PATCH 2/5] Revert "Added powerSaveMode (and some minor corrections)" This reverts commit 850cce0ec70e2b86ef22cf6e35a634816d81097e. --- .../Example19_PowerSaveMode.ino | 123 ---------- keywords.txt | 2 - src/SparkFun_Ublox_Arduino_Library.cpp | 223 +++++++----------- src/SparkFun_Ublox_Arduino_Library.h | 28 +-- 4 files changed, 98 insertions(+), 278 deletions(-) delete mode 100644 examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino diff --git a/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino b/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino deleted file mode 100644 index 7cb05aa..0000000 --- a/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino +++ /dev/null @@ -1,123 +0,0 @@ -/* - Power Save Mode - By: Paul Clark (PaulZC) - Date: December 18th, 2019 - - Based extensively on Example3_GetPosition - By: Nathan Seidle - SparkFun Electronics - Date: January 3rd, 2019 - License: MIT. See license file for more information but you can - basically do whatever you want with this code. - - This example shows how to put the Ublox module into power save mode and then - query its lat/long/altitude. We also turn off the NMEA output on the I2C port. - This decreases the amount of I2C traffic dramatically. - - ** When it is able to ** the module will reduce its current draw. - For the ZOE-M8Q with a passive antenna, you should see the current drop - from (approx.) 25-28mA to (approx.) 9mA when power save mode kicks in. - - Note: this will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported - - Note: Long/lat are large numbers because they are * 10^7. To convert lat/long - to something google maps understands simply divide the numbers by 10,000,000. We - do this so that we don't have to use floating point numbers. - - Leave NMEA parsing behind. Now you can simply ask the module for the datums you want! - - Feel like supporting open source hardware? - Buy a board from SparkFun! - ZED-F9P RTK2: https://www.sparkfun.com/products/15136 - NEO-M8P RTK: https://www.sparkfun.com/products/15005 - SAM-M8Q: https://www.sparkfun.com/products/15106 - - Hardware Connections: - Plug a Qwiic cable into the GPS and a BlackBoard - If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425) - Open the serial monitor at 115200 baud to see the output -*/ - -#include //Needed for I2C to GPS - -#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS -SFE_UBLOX_GPS myGPS; - -long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module. - -void setup() -{ - Serial.begin(115200); - while (!Serial); //Wait for user to open terminal - Serial.println("SparkFun Ublox Example"); - - Wire.begin(); - - if (myGPS.begin() == false) //Connect to the Ublox module using Wire port - { - Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); - while (1); - } - - //myGPS.enableDebugging(); // Uncomment this line to enable debug messages - - Serial.println(F("Waiting for a 3D fix...")); - - byte fixType = 0; - - while (fixType != 3) // Wait for a 3D fix - { - fixType = myGPS.getFixType(); // Get the fix type - Serial.print(F("Fix: ")); - Serial.print(fixType); - if(fixType == 0) Serial.print(F(" = No fix")); - else if(fixType == 1) Serial.print(F(" = Dead reckoning")); - else if(fixType == 2) Serial.print(F(" = 2D")); - else if(fixType == 3) Serial.print(F(" = 3D")); - else if(fixType == 4) Serial.print(F(" = GNSS + Dead reckoning")); - Serial.println(); - delay(1000); - } - - Serial.println(F("3D fix found! Engaging power save mode...")); - - // Put the GNSS into power save mode - // (If you want to disable power save mode, call myGPS.powerSaveMode(false) instead) - // This will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported - if (myGPS.powerSaveMode()) - { - Serial.println(F("Power Save Mode enabled.")); - } - else - { - Serial.println(F("***!!! Power Save Mode FAILED !!!***")); - } - - myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) - //myGPS.saveConfiguration(); //Uncomment this line to save the current settings to flash and BBR -} - -void loop() -{ - //Query module every 10 seconds so it is easier to monitor the current draw - if (millis() - lastTime > 10000) - { - lastTime = millis(); //Update the timer - - long latitude = myGPS.getLatitude(); - Serial.print(F("Lat: ")); - Serial.print(latitude); - - long longitude = myGPS.getLongitude(); - Serial.print(F(" Long: ")); - Serial.print(longitude); - Serial.print(F(" (degrees * 10^-7)")); - - long altitude = myGPS.getAltitude(); - Serial.print(F(" Alt: ")); - Serial.print(altitude); - Serial.print(F(" (mm)")); - - Serial.println(); - } -} diff --git a/keywords.txt b/keywords.txt index ec9899c..f0d1ed7 100644 --- a/keywords.txt +++ b/keywords.txt @@ -125,8 +125,6 @@ addGeofence KEYWORD2 clearGeofences KEYWORD2 getGeofenceState KEYWORD2 -powerSaveMode KEYWORD2 - ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index f48700d..5fc9e9d 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -1642,89 +1642,89 @@ boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, boolean implicitUpdate, uint16 //Add a new geofence using UBX-CFG-GEOFENCE boolean SFE_UBLOX_GPS::addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, byte confidence, byte pinPolarity, byte pin, uint16_t maxWait) { - if (currentGeofenceParams.numFences >= 4) return(false); // Quit if we already have four geofences defined - - // Store the new geofence parameters - currentGeofenceParams.lats[currentGeofenceParams.numFences] = latitude; - currentGeofenceParams.longs[currentGeofenceParams.numFences] = longitude; - currentGeofenceParams.rads[currentGeofenceParams.numFences] = radius; - currentGeofenceParams.numFences = currentGeofenceParams.numFences + 1; // Increment the number of fences - - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_GEOFENCE; - packetCfg.len = (currentGeofenceParams.numFences * 12) + 8; - packetCfg.startingSpot = 0; - - payloadCfg[0] = 0; // Message version = 0x00 - payloadCfg[1] = currentGeofenceParams.numFences; // numFences - payloadCfg[2] = confidence; // confLvl = Confidence level 0-4 (none, 68%, 95%, 99.7%, 99.99%) - payloadCfg[3] = 0; // reserved1 - if (pin > 0) - { - payloadCfg[4] = 1; // enable PIO combined fence state - } - else - { - payloadCfg[4] = 0; // disable PIO combined fence state - } - payloadCfg[5] = pinPolarity; // PIO pin polarity (0 = low means inside, 1 = low means outside (or unknown)) - payloadCfg[6] = pin; // PIO pin - payloadCfg[7] = 0; //reserved2 - payloadCfg[8] = currentGeofenceParams.lats[0] & 0xFF; - payloadCfg[9] = currentGeofenceParams.lats[0] >> 8; - payloadCfg[10] = currentGeofenceParams.lats[0] >> 16; - payloadCfg[11] = currentGeofenceParams.lats[0] >> 24; - payloadCfg[12] = currentGeofenceParams.longs[0] & 0xFF; - payloadCfg[13] = currentGeofenceParams.longs[0] >> 8; - payloadCfg[14] = currentGeofenceParams.longs[0] >> 16; - payloadCfg[15] = currentGeofenceParams.longs[0] >> 24; - payloadCfg[16] = currentGeofenceParams.rads[0] & 0xFF; - payloadCfg[17] = currentGeofenceParams.rads[0] >> 8; - payloadCfg[18] = currentGeofenceParams.rads[0] >> 16; - payloadCfg[19] = currentGeofenceParams.rads[0] >> 24; - if (currentGeofenceParams.numFences >= 2) { - payloadCfg[20] = currentGeofenceParams.lats[1] & 0xFF; - payloadCfg[21] = currentGeofenceParams.lats[1] >> 8; - payloadCfg[22] = currentGeofenceParams.lats[1] >> 16; - payloadCfg[23] = currentGeofenceParams.lats[1] >> 24; - payloadCfg[24] = currentGeofenceParams.longs[1] & 0xFF; - payloadCfg[25] = currentGeofenceParams.longs[1] >> 8; - payloadCfg[26] = currentGeofenceParams.longs[1] >> 16; - payloadCfg[27] = currentGeofenceParams.longs[1] >> 24; - payloadCfg[28] = currentGeofenceParams.rads[1] & 0xFF; - payloadCfg[29] = currentGeofenceParams.rads[1] >> 8; - payloadCfg[30] = currentGeofenceParams.rads[1] >> 16; - payloadCfg[31] = currentGeofenceParams.rads[1] >> 24; - } - if (currentGeofenceParams.numFences >= 3) { - payloadCfg[32] = currentGeofenceParams.lats[2] & 0xFF; - payloadCfg[33] = currentGeofenceParams.lats[2] >> 8; - payloadCfg[34] = currentGeofenceParams.lats[2] >> 16; - payloadCfg[35] = currentGeofenceParams.lats[2] >> 24; - payloadCfg[36] = currentGeofenceParams.longs[2] & 0xFF; - payloadCfg[37] = currentGeofenceParams.longs[2] >> 8; - payloadCfg[38] = currentGeofenceParams.longs[2] >> 16; - payloadCfg[39] = currentGeofenceParams.longs[2] >> 24; - payloadCfg[40] = currentGeofenceParams.rads[2] & 0xFF; - payloadCfg[41] = currentGeofenceParams.rads[2] >> 8; - payloadCfg[42] = currentGeofenceParams.rads[2] >> 16; - payloadCfg[43] = currentGeofenceParams.rads[2] >> 24; - } - if (currentGeofenceParams.numFences >= 4) { - payloadCfg[44] = currentGeofenceParams.lats[3] & 0xFF; - payloadCfg[45] = currentGeofenceParams.lats[3] >> 8; - payloadCfg[46] = currentGeofenceParams.lats[3] >> 16; - payloadCfg[47] = currentGeofenceParams.lats[3] >> 24; - payloadCfg[48] = currentGeofenceParams.longs[3] & 0xFF; - payloadCfg[49] = currentGeofenceParams.longs[3] >> 8; - payloadCfg[50] = currentGeofenceParams.longs[3] >> 16; - payloadCfg[51] = currentGeofenceParams.longs[3] >> 24; - payloadCfg[52] = currentGeofenceParams.rads[3] & 0xFF; - payloadCfg[53] = currentGeofenceParams.rads[3] >> 8; - payloadCfg[54] = currentGeofenceParams.rads[3] >> 16; - payloadCfg[55] = currentGeofenceParams.rads[3] >> 24; - } - return (sendCommand(packetCfg, maxWait)); //Wait for ack + if (currentGeofenceParams.numFences >= 4) return(false); // Quit if we already have four geofences defined + + // Store the new geofence parameters + currentGeofenceParams.lats[currentGeofenceParams.numFences] = latitude; + currentGeofenceParams.longs[currentGeofenceParams.numFences] = longitude; + currentGeofenceParams.rads[currentGeofenceParams.numFences] = radius; + currentGeofenceParams.numFences = currentGeofenceParams.numFences + 1; // Increment the number of fences + + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_GEOFENCE; + packetCfg.len = (currentGeofenceParams.numFences * 12) + 8; + packetCfg.startingSpot = 0; + + payloadCfg[0] = 0; // Message version = 0x00 + payloadCfg[1] = currentGeofenceParams.numFences; // numFences + payloadCfg[2] = confidence; // confLvl = Confidence level 0-4 (none, 68%, 95%, 99.7%, 99.99%) + payloadCfg[3] = 0; // reserved1 + if (pin > 0) + { + payloadCfg[4] = 1; // enable PIO combined fence state + } + else + { + payloadCfg[4] = 0; // disable PIO combined fence state + } + payloadCfg[5] = pinPolarity; // PIO pin polarity (0 = low means inside, 1 = low means outside (or unknown)) + payloadCfg[6] = pin; // PIO pin + payloadCfg[7] = 0; //reserved2 + payloadCfg[8] = currentGeofenceParams.lats[0] & 0xFF; + payloadCfg[9] = currentGeofenceParams.lats[0] >> 8; + payloadCfg[10] = currentGeofenceParams.lats[0] >> 16; + payloadCfg[11] = currentGeofenceParams.lats[0] >> 24; + payloadCfg[12] = currentGeofenceParams.longs[0] & 0xFF; + payloadCfg[13] = currentGeofenceParams.longs[0] >> 8; + payloadCfg[14] = currentGeofenceParams.longs[0] >> 16; + payloadCfg[15] = currentGeofenceParams.longs[0] >> 24; + payloadCfg[16] = currentGeofenceParams.rads[0] & 0xFF; + payloadCfg[17] = currentGeofenceParams.rads[0] >> 8; + payloadCfg[18] = currentGeofenceParams.rads[0] >> 16; + payloadCfg[19] = currentGeofenceParams.rads[0] >> 24; + if (currentGeofenceParams.numFences >= 2) { + payloadCfg[20] = currentGeofenceParams.lats[1] & 0xFF; + payloadCfg[21] = currentGeofenceParams.lats[1] >> 8; + payloadCfg[22] = currentGeofenceParams.lats[1] >> 16; + payloadCfg[23] = currentGeofenceParams.lats[1] >> 24; + payloadCfg[24] = currentGeofenceParams.longs[1] & 0xFF; + payloadCfg[25] = currentGeofenceParams.longs[1] >> 8; + payloadCfg[26] = currentGeofenceParams.longs[1] >> 16; + payloadCfg[27] = currentGeofenceParams.longs[1] >> 24; + payloadCfg[28] = currentGeofenceParams.rads[1] & 0xFF; + payloadCfg[29] = currentGeofenceParams.rads[1] >> 8; + payloadCfg[30] = currentGeofenceParams.rads[1] >> 16; + payloadCfg[31] = currentGeofenceParams.rads[1] >> 24; + } + if (currentGeofenceParams.numFences >= 3) { + payloadCfg[32] = currentGeofenceParams.lats[2] & 0xFF; + payloadCfg[33] = currentGeofenceParams.lats[2] >> 8; + payloadCfg[34] = currentGeofenceParams.lats[2] >> 16; + payloadCfg[35] = currentGeofenceParams.lats[2] >> 24; + payloadCfg[36] = currentGeofenceParams.longs[2] & 0xFF; + payloadCfg[37] = currentGeofenceParams.longs[2] >> 8; + payloadCfg[38] = currentGeofenceParams.longs[2] >> 16; + payloadCfg[39] = currentGeofenceParams.longs[2] >> 24; + payloadCfg[40] = currentGeofenceParams.rads[2] & 0xFF; + payloadCfg[41] = currentGeofenceParams.rads[2] >> 8; + payloadCfg[42] = currentGeofenceParams.rads[2] >> 16; + payloadCfg[43] = currentGeofenceParams.rads[2] >> 24; + } + if (currentGeofenceParams.numFences >= 4) { + payloadCfg[44] = currentGeofenceParams.lats[3] & 0xFF; + payloadCfg[45] = currentGeofenceParams.lats[3] >> 8; + payloadCfg[46] = currentGeofenceParams.lats[3] >> 16; + payloadCfg[47] = currentGeofenceParams.lats[3] >> 24; + payloadCfg[48] = currentGeofenceParams.longs[3] & 0xFF; + payloadCfg[49] = currentGeofenceParams.longs[3] >> 8; + payloadCfg[50] = currentGeofenceParams.longs[3] >> 16; + payloadCfg[51] = currentGeofenceParams.longs[3] >> 24; + payloadCfg[52] = currentGeofenceParams.rads[3] & 0xFF; + payloadCfg[53] = currentGeofenceParams.rads[3] >> 8; + payloadCfg[54] = currentGeofenceParams.rads[3] >> 16; + payloadCfg[55] = currentGeofenceParams.rads[3] >> 24; + } + return (sendCommand(packetCfg, maxWait)); //Wait for ack } //Clear all geofences using UBX-CFG-GEOFENCE @@ -1789,53 +1789,6 @@ boolean SFE_UBLOX_GPS::getGeofenceState(geofenceState ¤tGeofenceState, uin return(true); } -//Power Save Mode -//Enables/Disables Low Power Mode using UBX-CFG-RXM -boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) -{ - // Let's begin by checking the Protocol Version as UBX_CFG_RXM is not supported on the ZED (protocol >= 27) - uint8_t protVer = getProtocolVersionHigh(); - /* - if (_printDebug == true) - { - _debugSerial->print("Protocol version is "); - _debugSerial->println(protVer); - } - */ - if (protVer >= 27) - { - debugPrintln((char *)"powerSaveMode (UBX-CFG-RXM) is not supported by this protocol version"); - return (false); - } - - // Now let's change the power setting using UBX-CFG-RXM - packetCfg.cls = UBX_CLASS_CFG; - packetCfg.id = UBX_CFG_RXM; - packetCfg.len = 0; - packetCfg.startingSpot = 0; - - if (sendCommand(packetCfg, maxWait) == false) //Ask module for the current power management settings. Loads into payloadCfg. - return (false); - - // Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response) - // This is only required because we are doing two sendCommands in quick succession using the same class and ID - waitForResponse(UBX_CLASS_CFG, UBX_CFG_RXM, 100); // But we'll only wait for 100msec max - - if (power_save) - { - payloadCfg[1] = 1; // Power Save Mode - } - else - { - payloadCfg[1] = 0; // Continuous Mode - } - - packetCfg.len = 2; - packetCfg.startingSpot = 0; - - return (sendCommand(packetCfg, maxWait)); //Wait for ack -} - //Given a spot in the payload array, extract four bytes and build a long uint32_t SFE_UBLOX_GPS::extractLong(uint8_t spotToStart) { @@ -2180,7 +2133,7 @@ uint16_t SFE_UBLOX_GPS::getPDOP(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getProtocolVersionHigh(uint16_t maxWait) { if (moduleQueried.versionNumber == false) - getProtocolVersion(maxWait); + getProtocolVersion(); moduleQueried.versionNumber = false; return (versionHigh); } @@ -2190,7 +2143,7 @@ uint8_t SFE_UBLOX_GPS::getProtocolVersionHigh(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getProtocolVersionLow(uint16_t maxWait) { if (moduleQueried.versionNumber == false) - getProtocolVersion(maxWait); + getProtocolVersion(); moduleQueried.versionNumber = false; return (versionLow); } @@ -2213,10 +2166,6 @@ boolean SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait) if (sendCommand(packetCfg, maxWait) == false) return (false); //If command send fails then bail - // Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response) - // This is only required because we are doing multiple sendCommands in quick succession using the same class and ID - waitForResponse(UBX_CLASS_MON, UBX_MON_VER, 100); // But we'll only wait for 100msec max - if (_printDebug == true) { _debugSerial->print("Extension "); @@ -2236,7 +2185,7 @@ boolean SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait) { versionHigh = (payloadCfg[8] - '0') * 10 + (payloadCfg[9] - '0'); //Convert '18' to 18 versionLow = (payloadCfg[11] - '0') * 10 + (payloadCfg[12] - '0'); //Convert '00' to 00 - return (true); // This function returns a boolean (so we can't return versionLow) + return (versionLow); } } diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index efb3c5d..9d3c409 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -99,7 +99,6 @@ const uint8_t UBX_CFG_PRT = 0x00; //Used to configure port specifics const uint8_t UBX_CFG_RST = 0x04; //Used to reset device const uint8_t UBX_CFG_RATE = 0x08; //Used to set port baud rates const uint8_t UBX_CFG_CFG = 0x09; //Used to save current configuration -const uint8_t UBX_CFG_RXM = 0x11; //Used to set receiver power management (power save mode) const uint8_t UBX_CFG_VALSET = 0x8A; //Used for config of higher version Ublox modules (ie protocol v27 and above) const uint8_t UBX_CFG_VALGET = 0x8B; //Used for config of higher version Ublox modules (ie protocol v27 and above) const uint8_t UBX_CFG_VALDEL = 0x8C; //Used for config of higher version Ublox modules (ie protocol v27 and above) @@ -196,18 +195,18 @@ typedef struct // Struct to hold the results returned by getGeofenceState (returned by UBX-NAV-GEOFENCE) typedef struct { - uint8_t status; // Geofencing status: 0 - Geofencing not available or not reliable; 1 - Geofencing active - uint8_t numFences; // Number of geofences - uint8_t combState; // Combined (logical OR) state of all geofences: 0 - Unknown; 1 - Inside; 2 - Outside - uint8_t states[4]; // Geofence states: 0 - Unknown; 1 - Inside; 2 - Outside + uint8_t status; // Geofencing status: 0 - Geofencing not available or not reliable; 1 - Geofencing active + uint8_t numFences; // Number of geofences + uint8_t combState; // Combined (logical OR) state of all geofences: 0 - Unknown; 1 - Inside; 2 - Outside + uint8_t states[4]; // Geofence states: 0 - Unknown; 1 - Inside; 2 - Outside } geofenceState; // Struct to hold the current geofence parameters typedef struct { - uint8_t numFences; // Number of active geofences - int32_t lats[4]; // Latitudes of geofences (in degrees * 10^-7) - int32_t longs[4]; // Longitudes of geofences (in degrees * 10^-7) - uint32_t rads[4]; // Radii of geofences (in m * 10^-2) + uint8_t numFences; // Number of active geofences + int32_t lats[4]; // Latitudes of geofences (in degrees * 10^-7) + int32_t longs[4]; // Longitudes of geofences (in degrees * 10^-7) + uint32_t rads[4]; // Radii of geofences (in m * 10^-2) } geofenceParams; class SFE_UBLOX_GPS @@ -340,13 +339,10 @@ class SFE_UBLOX_GPS void debugPrint(char *message); //Safely print debug statements void debugPrintln(char *message); //Safely print debug statements - //Support for geofences - boolean addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, byte confidence = 0, byte pinPolarity = 0, byte pin = 0, uint16_t maxWait = 2000); // Add a new geofence - boolean clearGeofences(uint16_t maxWait = 2000); //Clears all geofences - boolean getGeofenceState(geofenceState ¤tGeofenceState, uint16_t maxWait = 2000); //Returns the combined geofence state - - //Power Save Mode - boolean powerSaveMode(bool power_save = true, uint16_t maxWait = 2000); + //Support for geofences + boolean addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, byte confidence = 0, byte pinPolarity = 0, byte pin = 0, uint16_t maxWait = 2000); // Add a new geofence + boolean clearGeofences(uint16_t maxWait = 2000); //Clears all geofences + boolean getGeofenceState(geofenceState ¤tGeofenceState, uint16_t maxWait = 2000); //Returns the combined geofence state //Survey-in specific controls struct svinStructure From 6364ea4ba79a8fe3b6919adb82f97bfd4ec3819f Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 22 Dec 2019 17:38:41 +0000 Subject: [PATCH 3/5] Added powerSaveMode (and some minor corrections) --- .../Example19_PowerSaveMode.ino | 123 ++++++++++++++++++ keywords.txt | 2 + src/SparkFun_Ublox_Arduino_Library.cpp | 57 +++++++- src/SparkFun_Ublox_Arduino_Library.h | 4 + 4 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino diff --git a/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino b/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino new file mode 100644 index 0000000..7cb05aa --- /dev/null +++ b/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino @@ -0,0 +1,123 @@ +/* + Power Save Mode + By: Paul Clark (PaulZC) + Date: December 18th, 2019 + + Based extensively on Example3_GetPosition + By: Nathan Seidle + SparkFun Electronics + Date: January 3rd, 2019 + License: MIT. See license file for more information but you can + basically do whatever you want with this code. + + This example shows how to put the Ublox module into power save mode and then + query its lat/long/altitude. We also turn off the NMEA output on the I2C port. + This decreases the amount of I2C traffic dramatically. + + ** When it is able to ** the module will reduce its current draw. + For the ZOE-M8Q with a passive antenna, you should see the current drop + from (approx.) 25-28mA to (approx.) 9mA when power save mode kicks in. + + Note: this will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported + + Note: Long/lat are large numbers because they are * 10^7. To convert lat/long + to something google maps understands simply divide the numbers by 10,000,000. We + do this so that we don't have to use floating point numbers. + + Leave NMEA parsing behind. Now you can simply ask the module for the datums you want! + + Feel like supporting open source hardware? + Buy a board from SparkFun! + ZED-F9P RTK2: https://www.sparkfun.com/products/15136 + NEO-M8P RTK: https://www.sparkfun.com/products/15005 + SAM-M8Q: https://www.sparkfun.com/products/15106 + + Hardware Connections: + Plug a Qwiic cable into the GPS and a BlackBoard + If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425) + Open the serial monitor at 115200 baud to see the output +*/ + +#include //Needed for I2C to GPS + +#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module. + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println("SparkFun Ublox Example"); + + Wire.begin(); + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1); + } + + //myGPS.enableDebugging(); // Uncomment this line to enable debug messages + + Serial.println(F("Waiting for a 3D fix...")); + + byte fixType = 0; + + while (fixType != 3) // Wait for a 3D fix + { + fixType = myGPS.getFixType(); // Get the fix type + Serial.print(F("Fix: ")); + Serial.print(fixType); + if(fixType == 0) Serial.print(F(" = No fix")); + else if(fixType == 1) Serial.print(F(" = Dead reckoning")); + else if(fixType == 2) Serial.print(F(" = 2D")); + else if(fixType == 3) Serial.print(F(" = 3D")); + else if(fixType == 4) Serial.print(F(" = GNSS + Dead reckoning")); + Serial.println(); + delay(1000); + } + + Serial.println(F("3D fix found! Engaging power save mode...")); + + // Put the GNSS into power save mode + // (If you want to disable power save mode, call myGPS.powerSaveMode(false) instead) + // This will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported + if (myGPS.powerSaveMode()) + { + Serial.println(F("Power Save Mode enabled.")); + } + else + { + Serial.println(F("***!!! Power Save Mode FAILED !!!***")); + } + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + //myGPS.saveConfiguration(); //Uncomment this line to save the current settings to flash and BBR +} + +void loop() +{ + //Query module every 10 seconds so it is easier to monitor the current draw + if (millis() - lastTime > 10000) + { + lastTime = millis(); //Update the timer + + long latitude = myGPS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGPS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGPS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + Serial.println(); + } +} diff --git a/keywords.txt b/keywords.txt index f0d1ed7..ec9899c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -125,6 +125,8 @@ addGeofence KEYWORD2 clearGeofences KEYWORD2 getGeofenceState KEYWORD2 +powerSaveMode KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index 5fc9e9d..afbce27 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -1789,6 +1789,53 @@ boolean SFE_UBLOX_GPS::getGeofenceState(geofenceState ¤tGeofenceState, uin return(true); } +//Power Save Mode +//Enables/Disables Low Power Mode using UBX-CFG-RXM +boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) +{ + // Let's begin by checking the Protocol Version as UBX_CFG_RXM is not supported on the ZED (protocol >= 27) + uint8_t protVer = getProtocolVersionHigh(); + /* + if (_printDebug == true) + { + _debugSerial->print("Protocol version is "); + _debugSerial->println(protVer); + } + */ + if (protVer >= 27) + { + debugPrintln((char *)"powerSaveMode (UBX-CFG-RXM) is not supported by this protocol version"); + return (false); + } + + // Now let's change the power setting using UBX-CFG-RXM + packetCfg.cls = UBX_CLASS_CFG; + packetCfg.id = UBX_CFG_RXM; + packetCfg.len = 0; + packetCfg.startingSpot = 0; + + if (sendCommand(packetCfg, maxWait) == false) //Ask module for the current power management settings. Loads into payloadCfg. + return (false); + + // Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response) + // This is only required because we are doing two sendCommands in quick succession using the same class and ID + waitForResponse(UBX_CLASS_CFG, UBX_CFG_RXM, 100); // But we'll only wait for 100msec max + + if (power_save) + { + payloadCfg[1] = 1; // Power Save Mode + } + else + { + payloadCfg[1] = 0; // Continuous Mode + } + + packetCfg.len = 2; + packetCfg.startingSpot = 0; + + return (sendCommand(packetCfg, maxWait)); //Wait for ack +} + //Given a spot in the payload array, extract four bytes and build a long uint32_t SFE_UBLOX_GPS::extractLong(uint8_t spotToStart) { @@ -2133,7 +2180,7 @@ uint16_t SFE_UBLOX_GPS::getPDOP(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getProtocolVersionHigh(uint16_t maxWait) { if (moduleQueried.versionNumber == false) - getProtocolVersion(); + getProtocolVersion(maxWait); moduleQueried.versionNumber = false; return (versionHigh); } @@ -2143,7 +2190,7 @@ uint8_t SFE_UBLOX_GPS::getProtocolVersionHigh(uint16_t maxWait) uint8_t SFE_UBLOX_GPS::getProtocolVersionLow(uint16_t maxWait) { if (moduleQueried.versionNumber == false) - getProtocolVersion(); + getProtocolVersion(maxWait); moduleQueried.versionNumber = false; return (versionLow); } @@ -2166,6 +2213,10 @@ boolean SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait) if (sendCommand(packetCfg, maxWait) == false) return (false); //If command send fails then bail + // Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response) + // This is only required because we are doing multiple sendCommands in quick succession using the same class and ID + waitForResponse(UBX_CLASS_MON, UBX_MON_VER, 100); // But we'll only wait for 100msec max + if (_printDebug == true) { _debugSerial->print("Extension "); @@ -2185,7 +2236,7 @@ boolean SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait) { versionHigh = (payloadCfg[8] - '0') * 10 + (payloadCfg[9] - '0'); //Convert '18' to 18 versionLow = (payloadCfg[11] - '0') * 10 + (payloadCfg[12] - '0'); //Convert '00' to 00 - return (versionLow); + return (true); // This function returns a boolean (so we can't return versionLow) } } diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index 9d3c409..b41e774 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -99,6 +99,7 @@ const uint8_t UBX_CFG_PRT = 0x00; //Used to configure port specifics const uint8_t UBX_CFG_RST = 0x04; //Used to reset device const uint8_t UBX_CFG_RATE = 0x08; //Used to set port baud rates const uint8_t UBX_CFG_CFG = 0x09; //Used to save current configuration +const uint8_t UBX_CFG_RXM = 0x11; //Used to set receiver power management (power save mode) const uint8_t UBX_CFG_VALSET = 0x8A; //Used for config of higher version Ublox modules (ie protocol v27 and above) const uint8_t UBX_CFG_VALGET = 0x8B; //Used for config of higher version Ublox modules (ie protocol v27 and above) const uint8_t UBX_CFG_VALDEL = 0x8C; //Used for config of higher version Ublox modules (ie protocol v27 and above) @@ -344,6 +345,9 @@ class SFE_UBLOX_GPS boolean clearGeofences(uint16_t maxWait = 2000); //Clears all geofences boolean getGeofenceState(geofenceState ¤tGeofenceState, uint16_t maxWait = 2000); //Returns the combined geofence state + //Power Save Mode + boolean powerSaveMode(bool power_save = true, uint16_t maxWait = 2000); + //Survey-in specific controls struct svinStructure { From 4f005a2521b03492b36204821fc5a868f2c9d08f Mon Sep 17 00:00:00 2001 From: Paul <5690545+PaulZC@users.noreply.github.com> Date: Sun, 22 Dec 2019 18:49:41 +0000 Subject: [PATCH 4/5] My bad! I forgot to pass down maxWait to getProtocolVersion too! --- src/SparkFun_Ublox_Arduino_Library.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index afbce27..34c9e5a 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -1794,7 +1794,7 @@ boolean SFE_UBLOX_GPS::getGeofenceState(geofenceState ¤tGeofenceState, uin boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait) { // Let's begin by checking the Protocol Version as UBX_CFG_RXM is not supported on the ZED (protocol >= 27) - uint8_t protVer = getProtocolVersionHigh(); + uint8_t protVer = getProtocolVersionHigh(maxWait); /* if (_printDebug == true) { From 9024f2e378792bbad0cd9d4b8e71d537f9c201c5 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 23 Dec 2019 10:38:56 -0700 Subject: [PATCH 5/5] Add menu to control power --- .../Example19_PowerSaveMode.ino | 90 +++++++++++-------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino b/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino index 7cb05aa..291fcc1 100644 --- a/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino +++ b/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino @@ -2,7 +2,7 @@ Power Save Mode By: Paul Clark (PaulZC) Date: December 18th, 2019 - + Based extensively on Example3_GetPosition By: Nathan Seidle SparkFun Electronics @@ -21,7 +21,7 @@ Note: this will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported Note: Long/lat are large numbers because they are * 10^7. To convert lat/long - to something google maps understands simply divide the numbers by 10,000,000. We + to something google maps understands simply divide the numbers by 10,000,000. We do this so that we don't have to use floating point numbers. Leave NMEA parsing behind. Now you can simply ask the module for the datums you want! @@ -48,7 +48,8 @@ long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox m void setup() { Serial.begin(115200); - while (!Serial); //Wait for user to open terminal + while (!Serial) + ; //Wait for user to open terminal Serial.println("SparkFun Ublox Example"); Wire.begin(); @@ -56,56 +57,67 @@ void setup() if (myGPS.begin() == false) //Connect to the Ublox module using Wire port { Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); - while (1); + while (1) + ; } //myGPS.enableDebugging(); // Uncomment this line to enable debug messages - Serial.println(F("Waiting for a 3D fix...")); - - byte fixType = 0; - - while (fixType != 3) // Wait for a 3D fix - { - fixType = myGPS.getFixType(); // Get the fix type - Serial.print(F("Fix: ")); - Serial.print(fixType); - if(fixType == 0) Serial.print(F(" = No fix")); - else if(fixType == 1) Serial.print(F(" = Dead reckoning")); - else if(fixType == 2) Serial.print(F(" = 2D")); - else if(fixType == 3) Serial.print(F(" = 3D")); - else if(fixType == 4) Serial.print(F(" = GNSS + Dead reckoning")); - Serial.println(); - delay(1000); - } - - Serial.println(F("3D fix found! Engaging power save mode...")); - - // Put the GNSS into power save mode - // (If you want to disable power save mode, call myGPS.powerSaveMode(false) instead) - // This will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported - if (myGPS.powerSaveMode()) - { - Serial.println(F("Power Save Mode enabled.")); - } - else - { - Serial.println(F("***!!! Power Save Mode FAILED !!!***")); - } - myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) //myGPS.saveConfiguration(); //Uncomment this line to save the current settings to flash and BBR + + Serial.println("Power save example."); + Serial.println("1) Enable power saving"); + Serial.println("2) Disable power saving"); } void loop() { + if (Serial.available()) + { + byte incoming = Serial.read(); + + if (incoming == '1') + { + // Put the GNSS into power save mode + // (If you want to disable power save mode, call myGPS.powerSaveMode(false) instead) + // This will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported + if (myGPS.powerSaveMode()) + Serial.println(F("Power Save Mode enabled.")); + else + Serial.println(F("***!!! Power Save Mode FAILED !!!***")); + } + else if (incoming == '2') + { + //Go to normal power mode (not power saving mode) + if (myGPS.powerSaveMode(false)) + Serial.println(F("Power Save Mode disabled.")); + else + Serial.println(F("***!!! Power Save Disable FAILED !!!***")); + } + } + //Query module every 10 seconds so it is easier to monitor the current draw if (millis() - lastTime > 10000) { lastTime = millis(); //Update the timer - + + byte fixType = myGPS.getFixType(); // Get the fix type + Serial.print(F("Fix: ")); + Serial.print(fixType); + if (fixType == 0) + Serial.print(F("(No fix)")); + else if (fixType == 1) + Serial.print(F("(Dead reckoning)")); + else if (fixType == 2) + Serial.print(F("(2D)")); + else if (fixType == 3) + Serial.print(F("(3D)")); + else if (fixType == 4) + Serial.print(F("(GNSS + Dead reckoning)")); + long latitude = myGPS.getLatitude(); - Serial.print(F("Lat: ")); + Serial.print(F(" Lat: ")); Serial.print(latitude); long longitude = myGPS.getLongitude(); @@ -120,4 +132,4 @@ void loop() Serial.println(); } -} +} \ No newline at end of file