diff --git a/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino b/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino new file mode 100644 index 0000000..291fcc1 --- /dev/null +++ b/examples/Example19_PowerSaveMode/Example19_PowerSaveMode.ino @@ -0,0 +1,135 @@ +/* + 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 + + 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(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(); + } +} \ No newline at end of file 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..34c9e5a 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(maxWait); + /* + 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 {