Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Commit 850cce0

Browse files
committed
Added powerSaveMode (and some minor corrections)
1 parent ab0bf7a commit 850cce0

File tree

4 files changed

+278
-98
lines changed

4 files changed

+278
-98
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
Power Save Mode
3+
By: Paul Clark (PaulZC)
4+
Date: December 18th, 2019
5+
6+
Based extensively on Example3_GetPosition
7+
By: Nathan Seidle
8+
SparkFun Electronics
9+
Date: January 3rd, 2019
10+
License: MIT. See license file for more information but you can
11+
basically do whatever you want with this code.
12+
13+
This example shows how to put the Ublox module into power save mode and then
14+
query its lat/long/altitude. We also turn off the NMEA output on the I2C port.
15+
This decreases the amount of I2C traffic dramatically.
16+
17+
** When it is able to ** the module will reduce its current draw.
18+
For the ZOE-M8Q with a passive antenna, you should see the current drop
19+
from (approx.) 25-28mA to (approx.) 9mA when power save mode kicks in.
20+
21+
Note: this will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported
22+
23+
Note: Long/lat are large numbers because they are * 10^7. To convert lat/long
24+
to something google maps understands simply divide the numbers by 10,000,000. We
25+
do this so that we don't have to use floating point numbers.
26+
27+
Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!
28+
29+
Feel like supporting open source hardware?
30+
Buy a board from SparkFun!
31+
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
32+
NEO-M8P RTK: https://www.sparkfun.com/products/15005
33+
SAM-M8Q: https://www.sparkfun.com/products/15106
34+
35+
Hardware Connections:
36+
Plug a Qwiic cable into the GPS and a BlackBoard
37+
If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
38+
Open the serial monitor at 115200 baud to see the output
39+
*/
40+
41+
#include <Wire.h> //Needed for I2C to GPS
42+
43+
#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS
44+
SFE_UBLOX_GPS myGPS;
45+
46+
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module.
47+
48+
void setup()
49+
{
50+
Serial.begin(115200);
51+
while (!Serial); //Wait for user to open terminal
52+
Serial.println("SparkFun Ublox Example");
53+
54+
Wire.begin();
55+
56+
if (myGPS.begin() == false) //Connect to the Ublox module using Wire port
57+
{
58+
Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing."));
59+
while (1);
60+
}
61+
62+
//myGPS.enableDebugging(); // Uncomment this line to enable debug messages
63+
64+
Serial.println(F("Waiting for a 3D fix..."));
65+
66+
byte fixType = 0;
67+
68+
while (fixType != 3) // Wait for a 3D fix
69+
{
70+
fixType = myGPS.getFixType(); // Get the fix type
71+
Serial.print(F("Fix: "));
72+
Serial.print(fixType);
73+
if(fixType == 0) Serial.print(F(" = No fix"));
74+
else if(fixType == 1) Serial.print(F(" = Dead reckoning"));
75+
else if(fixType == 2) Serial.print(F(" = 2D"));
76+
else if(fixType == 3) Serial.print(F(" = 3D"));
77+
else if(fixType == 4) Serial.print(F(" = GNSS + Dead reckoning"));
78+
Serial.println();
79+
delay(1000);
80+
}
81+
82+
Serial.println(F("3D fix found! Engaging power save mode..."));
83+
84+
// Put the GNSS into power save mode
85+
// (If you want to disable power save mode, call myGPS.powerSaveMode(false) instead)
86+
// This will fail on the ZED (protocol version >= 27) as UBX-CFG-RXM is not supported
87+
if (myGPS.powerSaveMode())
88+
{
89+
Serial.println(F("Power Save Mode enabled."));
90+
}
91+
else
92+
{
93+
Serial.println(F("***!!! Power Save Mode FAILED !!!***"));
94+
}
95+
96+
myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
97+
//myGPS.saveConfiguration(); //Uncomment this line to save the current settings to flash and BBR
98+
}
99+
100+
void loop()
101+
{
102+
//Query module every 10 seconds so it is easier to monitor the current draw
103+
if (millis() - lastTime > 10000)
104+
{
105+
lastTime = millis(); //Update the timer
106+
107+
long latitude = myGPS.getLatitude();
108+
Serial.print(F("Lat: "));
109+
Serial.print(latitude);
110+
111+
long longitude = myGPS.getLongitude();
112+
Serial.print(F(" Long: "));
113+
Serial.print(longitude);
114+
Serial.print(F(" (degrees * 10^-7)"));
115+
116+
long altitude = myGPS.getAltitude();
117+
Serial.print(F(" Alt: "));
118+
Serial.print(altitude);
119+
Serial.print(F(" (mm)"));
120+
121+
Serial.println();
122+
}
123+
}

keywords.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ addGeofence KEYWORD2
125125
clearGeofences KEYWORD2
126126
getGeofenceState KEYWORD2
127127

128+
powerSaveMode KEYWORD2
129+
128130
#######################################
129131
# Constants (LITERAL1)
130132
#######################################

src/SparkFun_Ublox_Arduino_Library.cpp

Lines changed: 137 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,89 +1642,89 @@ boolean SFE_UBLOX_GPS::setAutoPVT(boolean enable, boolean implicitUpdate, uint16
16421642
//Add a new geofence using UBX-CFG-GEOFENCE
16431643
boolean SFE_UBLOX_GPS::addGeofence(int32_t latitude, int32_t longitude, uint32_t radius, byte confidence, byte pinPolarity, byte pin, uint16_t maxWait)
16441644
{
1645-
if (currentGeofenceParams.numFences >= 4) return(false); // Quit if we already have four geofences defined
1646-
1647-
// Store the new geofence parameters
1648-
currentGeofenceParams.lats[currentGeofenceParams.numFences] = latitude;
1649-
currentGeofenceParams.longs[currentGeofenceParams.numFences] = longitude;
1650-
currentGeofenceParams.rads[currentGeofenceParams.numFences] = radius;
1651-
currentGeofenceParams.numFences = currentGeofenceParams.numFences + 1; // Increment the number of fences
1652-
1653-
packetCfg.cls = UBX_CLASS_CFG;
1654-
packetCfg.id = UBX_CFG_GEOFENCE;
1655-
packetCfg.len = (currentGeofenceParams.numFences * 12) + 8;
1656-
packetCfg.startingSpot = 0;
1657-
1658-
payloadCfg[0] = 0; // Message version = 0x00
1659-
payloadCfg[1] = currentGeofenceParams.numFences; // numFences
1660-
payloadCfg[2] = confidence; // confLvl = Confidence level 0-4 (none, 68%, 95%, 99.7%, 99.99%)
1661-
payloadCfg[3] = 0; // reserved1
1662-
if (pin > 0)
1663-
{
1664-
payloadCfg[4] = 1; // enable PIO combined fence state
1665-
}
1666-
else
1667-
{
1668-
payloadCfg[4] = 0; // disable PIO combined fence state
1669-
}
1670-
payloadCfg[5] = pinPolarity; // PIO pin polarity (0 = low means inside, 1 = low means outside (or unknown))
1671-
payloadCfg[6] = pin; // PIO pin
1672-
payloadCfg[7] = 0; //reserved2
1673-
payloadCfg[8] = currentGeofenceParams.lats[0] & 0xFF;
1674-
payloadCfg[9] = currentGeofenceParams.lats[0] >> 8;
1675-
payloadCfg[10] = currentGeofenceParams.lats[0] >> 16;
1676-
payloadCfg[11] = currentGeofenceParams.lats[0] >> 24;
1677-
payloadCfg[12] = currentGeofenceParams.longs[0] & 0xFF;
1678-
payloadCfg[13] = currentGeofenceParams.longs[0] >> 8;
1679-
payloadCfg[14] = currentGeofenceParams.longs[0] >> 16;
1680-
payloadCfg[15] = currentGeofenceParams.longs[0] >> 24;
1681-
payloadCfg[16] = currentGeofenceParams.rads[0] & 0xFF;
1682-
payloadCfg[17] = currentGeofenceParams.rads[0] >> 8;
1683-
payloadCfg[18] = currentGeofenceParams.rads[0] >> 16;
1684-
payloadCfg[19] = currentGeofenceParams.rads[0] >> 24;
1685-
if (currentGeofenceParams.numFences >= 2) {
1686-
payloadCfg[20] = currentGeofenceParams.lats[1] & 0xFF;
1687-
payloadCfg[21] = currentGeofenceParams.lats[1] >> 8;
1688-
payloadCfg[22] = currentGeofenceParams.lats[1] >> 16;
1689-
payloadCfg[23] = currentGeofenceParams.lats[1] >> 24;
1690-
payloadCfg[24] = currentGeofenceParams.longs[1] & 0xFF;
1691-
payloadCfg[25] = currentGeofenceParams.longs[1] >> 8;
1692-
payloadCfg[26] = currentGeofenceParams.longs[1] >> 16;
1693-
payloadCfg[27] = currentGeofenceParams.longs[1] >> 24;
1694-
payloadCfg[28] = currentGeofenceParams.rads[1] & 0xFF;
1695-
payloadCfg[29] = currentGeofenceParams.rads[1] >> 8;
1696-
payloadCfg[30] = currentGeofenceParams.rads[1] >> 16;
1697-
payloadCfg[31] = currentGeofenceParams.rads[1] >> 24;
1698-
}
1699-
if (currentGeofenceParams.numFences >= 3) {
1700-
payloadCfg[32] = currentGeofenceParams.lats[2] & 0xFF;
1701-
payloadCfg[33] = currentGeofenceParams.lats[2] >> 8;
1702-
payloadCfg[34] = currentGeofenceParams.lats[2] >> 16;
1703-
payloadCfg[35] = currentGeofenceParams.lats[2] >> 24;
1704-
payloadCfg[36] = currentGeofenceParams.longs[2] & 0xFF;
1705-
payloadCfg[37] = currentGeofenceParams.longs[2] >> 8;
1706-
payloadCfg[38] = currentGeofenceParams.longs[2] >> 16;
1707-
payloadCfg[39] = currentGeofenceParams.longs[2] >> 24;
1708-
payloadCfg[40] = currentGeofenceParams.rads[2] & 0xFF;
1709-
payloadCfg[41] = currentGeofenceParams.rads[2] >> 8;
1710-
payloadCfg[42] = currentGeofenceParams.rads[2] >> 16;
1711-
payloadCfg[43] = currentGeofenceParams.rads[2] >> 24;
1712-
}
1713-
if (currentGeofenceParams.numFences >= 4) {
1714-
payloadCfg[44] = currentGeofenceParams.lats[3] & 0xFF;
1715-
payloadCfg[45] = currentGeofenceParams.lats[3] >> 8;
1716-
payloadCfg[46] = currentGeofenceParams.lats[3] >> 16;
1717-
payloadCfg[47] = currentGeofenceParams.lats[3] >> 24;
1718-
payloadCfg[48] = currentGeofenceParams.longs[3] & 0xFF;
1719-
payloadCfg[49] = currentGeofenceParams.longs[3] >> 8;
1720-
payloadCfg[50] = currentGeofenceParams.longs[3] >> 16;
1721-
payloadCfg[51] = currentGeofenceParams.longs[3] >> 24;
1722-
payloadCfg[52] = currentGeofenceParams.rads[3] & 0xFF;
1723-
payloadCfg[53] = currentGeofenceParams.rads[3] >> 8;
1724-
payloadCfg[54] = currentGeofenceParams.rads[3] >> 16;
1725-
payloadCfg[55] = currentGeofenceParams.rads[3] >> 24;
1726-
}
1727-
return (sendCommand(packetCfg, maxWait)); //Wait for ack
1645+
if (currentGeofenceParams.numFences >= 4) return(false); // Quit if we already have four geofences defined
1646+
1647+
// Store the new geofence parameters
1648+
currentGeofenceParams.lats[currentGeofenceParams.numFences] = latitude;
1649+
currentGeofenceParams.longs[currentGeofenceParams.numFences] = longitude;
1650+
currentGeofenceParams.rads[currentGeofenceParams.numFences] = radius;
1651+
currentGeofenceParams.numFences = currentGeofenceParams.numFences + 1; // Increment the number of fences
1652+
1653+
packetCfg.cls = UBX_CLASS_CFG;
1654+
packetCfg.id = UBX_CFG_GEOFENCE;
1655+
packetCfg.len = (currentGeofenceParams.numFences * 12) + 8;
1656+
packetCfg.startingSpot = 0;
1657+
1658+
payloadCfg[0] = 0; // Message version = 0x00
1659+
payloadCfg[1] = currentGeofenceParams.numFences; // numFences
1660+
payloadCfg[2] = confidence; // confLvl = Confidence level 0-4 (none, 68%, 95%, 99.7%, 99.99%)
1661+
payloadCfg[3] = 0; // reserved1
1662+
if (pin > 0)
1663+
{
1664+
payloadCfg[4] = 1; // enable PIO combined fence state
1665+
}
1666+
else
1667+
{
1668+
payloadCfg[4] = 0; // disable PIO combined fence state
1669+
}
1670+
payloadCfg[5] = pinPolarity; // PIO pin polarity (0 = low means inside, 1 = low means outside (or unknown))
1671+
payloadCfg[6] = pin; // PIO pin
1672+
payloadCfg[7] = 0; //reserved2
1673+
payloadCfg[8] = currentGeofenceParams.lats[0] & 0xFF;
1674+
payloadCfg[9] = currentGeofenceParams.lats[0] >> 8;
1675+
payloadCfg[10] = currentGeofenceParams.lats[0] >> 16;
1676+
payloadCfg[11] = currentGeofenceParams.lats[0] >> 24;
1677+
payloadCfg[12] = currentGeofenceParams.longs[0] & 0xFF;
1678+
payloadCfg[13] = currentGeofenceParams.longs[0] >> 8;
1679+
payloadCfg[14] = currentGeofenceParams.longs[0] >> 16;
1680+
payloadCfg[15] = currentGeofenceParams.longs[0] >> 24;
1681+
payloadCfg[16] = currentGeofenceParams.rads[0] & 0xFF;
1682+
payloadCfg[17] = currentGeofenceParams.rads[0] >> 8;
1683+
payloadCfg[18] = currentGeofenceParams.rads[0] >> 16;
1684+
payloadCfg[19] = currentGeofenceParams.rads[0] >> 24;
1685+
if (currentGeofenceParams.numFences >= 2) {
1686+
payloadCfg[20] = currentGeofenceParams.lats[1] & 0xFF;
1687+
payloadCfg[21] = currentGeofenceParams.lats[1] >> 8;
1688+
payloadCfg[22] = currentGeofenceParams.lats[1] >> 16;
1689+
payloadCfg[23] = currentGeofenceParams.lats[1] >> 24;
1690+
payloadCfg[24] = currentGeofenceParams.longs[1] & 0xFF;
1691+
payloadCfg[25] = currentGeofenceParams.longs[1] >> 8;
1692+
payloadCfg[26] = currentGeofenceParams.longs[1] >> 16;
1693+
payloadCfg[27] = currentGeofenceParams.longs[1] >> 24;
1694+
payloadCfg[28] = currentGeofenceParams.rads[1] & 0xFF;
1695+
payloadCfg[29] = currentGeofenceParams.rads[1] >> 8;
1696+
payloadCfg[30] = currentGeofenceParams.rads[1] >> 16;
1697+
payloadCfg[31] = currentGeofenceParams.rads[1] >> 24;
1698+
}
1699+
if (currentGeofenceParams.numFences >= 3) {
1700+
payloadCfg[32] = currentGeofenceParams.lats[2] & 0xFF;
1701+
payloadCfg[33] = currentGeofenceParams.lats[2] >> 8;
1702+
payloadCfg[34] = currentGeofenceParams.lats[2] >> 16;
1703+
payloadCfg[35] = currentGeofenceParams.lats[2] >> 24;
1704+
payloadCfg[36] = currentGeofenceParams.longs[2] & 0xFF;
1705+
payloadCfg[37] = currentGeofenceParams.longs[2] >> 8;
1706+
payloadCfg[38] = currentGeofenceParams.longs[2] >> 16;
1707+
payloadCfg[39] = currentGeofenceParams.longs[2] >> 24;
1708+
payloadCfg[40] = currentGeofenceParams.rads[2] & 0xFF;
1709+
payloadCfg[41] = currentGeofenceParams.rads[2] >> 8;
1710+
payloadCfg[42] = currentGeofenceParams.rads[2] >> 16;
1711+
payloadCfg[43] = currentGeofenceParams.rads[2] >> 24;
1712+
}
1713+
if (currentGeofenceParams.numFences >= 4) {
1714+
payloadCfg[44] = currentGeofenceParams.lats[3] & 0xFF;
1715+
payloadCfg[45] = currentGeofenceParams.lats[3] >> 8;
1716+
payloadCfg[46] = currentGeofenceParams.lats[3] >> 16;
1717+
payloadCfg[47] = currentGeofenceParams.lats[3] >> 24;
1718+
payloadCfg[48] = currentGeofenceParams.longs[3] & 0xFF;
1719+
payloadCfg[49] = currentGeofenceParams.longs[3] >> 8;
1720+
payloadCfg[50] = currentGeofenceParams.longs[3] >> 16;
1721+
payloadCfg[51] = currentGeofenceParams.longs[3] >> 24;
1722+
payloadCfg[52] = currentGeofenceParams.rads[3] & 0xFF;
1723+
payloadCfg[53] = currentGeofenceParams.rads[3] >> 8;
1724+
payloadCfg[54] = currentGeofenceParams.rads[3] >> 16;
1725+
payloadCfg[55] = currentGeofenceParams.rads[3] >> 24;
1726+
}
1727+
return (sendCommand(packetCfg, maxWait)); //Wait for ack
17281728
}
17291729

17301730
//Clear all geofences using UBX-CFG-GEOFENCE
@@ -1789,6 +1789,53 @@ boolean SFE_UBLOX_GPS::getGeofenceState(geofenceState &currentGeofenceState, uin
17891789
return(true);
17901790
}
17911791

1792+
//Power Save Mode
1793+
//Enables/Disables Low Power Mode using UBX-CFG-RXM
1794+
boolean SFE_UBLOX_GPS::powerSaveMode(bool power_save, uint16_t maxWait)
1795+
{
1796+
// Let's begin by checking the Protocol Version as UBX_CFG_RXM is not supported on the ZED (protocol >= 27)
1797+
uint8_t protVer = getProtocolVersionHigh();
1798+
/*
1799+
if (_printDebug == true)
1800+
{
1801+
_debugSerial->print("Protocol version is ");
1802+
_debugSerial->println(protVer);
1803+
}
1804+
*/
1805+
if (protVer >= 27)
1806+
{
1807+
debugPrintln((char *)"powerSaveMode (UBX-CFG-RXM) is not supported by this protocol version");
1808+
return (false);
1809+
}
1810+
1811+
// Now let's change the power setting using UBX-CFG-RXM
1812+
packetCfg.cls = UBX_CLASS_CFG;
1813+
packetCfg.id = UBX_CFG_RXM;
1814+
packetCfg.len = 0;
1815+
packetCfg.startingSpot = 0;
1816+
1817+
if (sendCommand(packetCfg, maxWait) == false) //Ask module for the current power management settings. Loads into payloadCfg.
1818+
return (false);
1819+
1820+
// Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response)
1821+
// This is only required because we are doing two sendCommands in quick succession using the same class and ID
1822+
waitForResponse(UBX_CLASS_CFG, UBX_CFG_RXM, 100); // But we'll only wait for 100msec max
1823+
1824+
if (power_save)
1825+
{
1826+
payloadCfg[1] = 1; // Power Save Mode
1827+
}
1828+
else
1829+
{
1830+
payloadCfg[1] = 0; // Continuous Mode
1831+
}
1832+
1833+
packetCfg.len = 2;
1834+
packetCfg.startingSpot = 0;
1835+
1836+
return (sendCommand(packetCfg, maxWait)); //Wait for ack
1837+
}
1838+
17921839
//Given a spot in the payload array, extract four bytes and build a long
17931840
uint32_t SFE_UBLOX_GPS::extractLong(uint8_t spotToStart)
17941841
{
@@ -2133,7 +2180,7 @@ uint16_t SFE_UBLOX_GPS::getPDOP(uint16_t maxWait)
21332180
uint8_t SFE_UBLOX_GPS::getProtocolVersionHigh(uint16_t maxWait)
21342181
{
21352182
if (moduleQueried.versionNumber == false)
2136-
getProtocolVersion();
2183+
getProtocolVersion(maxWait);
21372184
moduleQueried.versionNumber = false;
21382185
return (versionHigh);
21392186
}
@@ -2143,7 +2190,7 @@ uint8_t SFE_UBLOX_GPS::getProtocolVersionHigh(uint16_t maxWait)
21432190
uint8_t SFE_UBLOX_GPS::getProtocolVersionLow(uint16_t maxWait)
21442191
{
21452192
if (moduleQueried.versionNumber == false)
2146-
getProtocolVersion();
2193+
getProtocolVersion(maxWait);
21472194
moduleQueried.versionNumber = false;
21482195
return (versionLow);
21492196
}
@@ -2166,6 +2213,10 @@ boolean SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait)
21662213
if (sendCommand(packetCfg, maxWait) == false)
21672214
return (false); //If command send fails then bail
21682215

2216+
// Let's make sure we wait for the ACK too (sendCommand will have returned as soon as the module sent its response)
2217+
// This is only required because we are doing multiple sendCommands in quick succession using the same class and ID
2218+
waitForResponse(UBX_CLASS_MON, UBX_MON_VER, 100); // But we'll only wait for 100msec max
2219+
21692220
if (_printDebug == true)
21702221
{
21712222
_debugSerial->print("Extension ");
@@ -2185,7 +2236,7 @@ boolean SFE_UBLOX_GPS::getProtocolVersion(uint16_t maxWait)
21852236
{
21862237
versionHigh = (payloadCfg[8] - '0') * 10 + (payloadCfg[9] - '0'); //Convert '18' to 18
21872238
versionLow = (payloadCfg[11] - '0') * 10 + (payloadCfg[12] - '0'); //Convert '00' to 00
2188-
return (versionLow);
2239+
return (true); // This function returns a boolean (so we can't return versionLow)
21892240
}
21902241
}
21912242

0 commit comments

Comments
 (0)