A driver for the MAX8U GPS by uBlox. Provides core functionality. Communicates through I2C.
MAX8U Driver
This driver supports a wide range of functions provided by the MAX8U chip. Most of the essential features are supported. It lays a framework to add more commands easily, with only a little extra work.
Driver was originally made for the USC Rocket Propulsion Lab by Adhyyan Sekhsaria and Jamie Smith
Features
Currently supports:
- Getting coordinates in latitude, longitude, accuracy...
- Velocity measurements in each axis
- Individual satellite information
- Time of last message
- Antenna Power Status
- GPS Fix Quality
- Save configuration in memory
Documentation
Full documentation is available here
Usage
Code Structure:
In factory settings, the module is not configured to send any messages. For the GPS to give updates, we need to configure it by sending messages using setMessageEnabled() which internally calls sendMessage() and waitForAck().
calling configure() once will enable a few useful messages, and save this configuration in the MAX8U non-volatile memory.
update() to be called periodically by the user. Processes and reads all the messages currently stored in the GPS. Calls processMessage() on every message. processMessage(): processes the message currently in the buffer by calling the respective functions. Each message is read, and its relevant information is then stored in the public variables.
By default, the GPS sends messages in NMEA format (but we reconfigure it to UBX format), so readNextMessage() has to determine which format the message is.
define the macro MAX8U_DEBUG to enable printing out to message information to the debug port. If not defined, will only print error messages to the debug port.
Example
Outputting Coordinates, Velocity and Time from GPS
#include "MAX8U.h" int main(){ MAX8U gps(&pc, PIN_I2C_SDA, PIN_I2C_SCL, p25); bool booted = gps.begin(); if(!booted){ //handle error } booted = gps.configure(); if(!booted){ //handle error } while(true){ bool newMessageRcvd = gps.update(); pc.printf(">Position: %.06f %c, %.06f %c, Height %.02f m\r\n", std::abs(gps.latitude), gps.latitude > 0 ? 'N' : 'S', std::abs(gps.longitude), gps.longitude > 0 ? 'E' : 'W', gps.height); // velocity pc.printf(">Velocity: %.02f m/s N, %.02f m/s E, %.02f m/s Down\r\n", gps.northVel * .02f, gps.eastVel * .02f, gps.downVel * .02f); // accuracy pc.printf(">Fix: Quality: %" PRIu8 ", Num Satellites: %" PRIu8 ", Position Accuracy: %.02f m\r\n", static_cast<uint8_t>(gps.fixQuality), gps.numSatellites, gps.posAccuracy); // time pc.printf(">Time: %" PRIu8 "/%" PRIu8"/%" PRIu16" %" PRIu8":%" PRIu8 ":%" PRIu8 "\r\n", gps.month, gps.day, gps.year, gps.hour, gps.minute, gps.second); } }
MAX8U.cpp@3:b51460af3259, 2020-01-07 (annotated)
- Committer:
- adhyyan
- Date:
- Tue Jan 07 10:49:40 2020 +0000
- Revision:
- 3:b51460af3259
- Parent:
- 0:7f603f221713
Added Example Code
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
adhyyan | 0:7f603f221713 | 1 | //MAX 8U GPS Driver |
adhyyan | 0:7f603f221713 | 2 | |
adhyyan | 0:7f603f221713 | 3 | //Author: Adhyyan Sekhsaria, Jamie Smith |
adhyyan | 0:7f603f221713 | 4 | |
adhyyan | 0:7f603f221713 | 5 | //Written with the help of the following data sheets: |
adhyyan | 0:7f603f221713 | 6 | //https://www.u-blox.com/sites/default/files/MAX-8-M8-FW3_HardwareIntegrationManual_%28UBX-15030059%29.pdf |
adhyyan | 0:7f603f221713 | 7 | //https://www.u-blox.com/en/docs/UBX-13003221 |
adhyyan | 0:7f603f221713 | 8 | |
adhyyan | 0:7f603f221713 | 9 | #include "MAX8U.h" |
adhyyan | 0:7f603f221713 | 10 | |
adhyyan | 0:7f603f221713 | 11 | #include <cinttypes> |
adhyyan | 0:7f603f221713 | 12 | #include <algorithm> |
adhyyan | 0:7f603f221713 | 13 | |
adhyyan | 0:7f603f221713 | 14 | #define MAX8U_DEBUG 1 |
adhyyan | 0:7f603f221713 | 15 | |
adhyyan | 0:7f603f221713 | 16 | const char* GNSSNames[] = {"GPS", "SBAS", "Galileo", "BeiDou", "IMES", "QZSS", "GLONASS"}; |
adhyyan | 0:7f603f221713 | 17 | |
adhyyan | 0:7f603f221713 | 18 | const char *MAX8U::SatelliteInfo::getGNSSName() |
adhyyan | 0:7f603f221713 | 19 | { |
adhyyan | 0:7f603f221713 | 20 | return GNSSNames[static_cast<uint8_t>(gnss)]; |
adhyyan | 0:7f603f221713 | 21 | } |
adhyyan | 0:7f603f221713 | 22 | |
adhyyan | 0:7f603f221713 | 23 | |
adhyyan | 0:7f603f221713 | 24 | MAX8U::MAX8U(Serial *debugPort, PinName user_SDApin, PinName user_SCLpin, PinName user_RSTPin, |
adhyyan | 0:7f603f221713 | 25 | uint8_t i2cAddress, int i2cPortSpeed) : |
adhyyan | 0:7f603f221713 | 26 | _debugPort(debugPort), |
adhyyan | 0:7f603f221713 | 27 | _i2cPort(user_SDApin, user_SCLpin), |
adhyyan | 0:7f603f221713 | 28 | _i2cAddress(i2cAddress), |
adhyyan | 0:7f603f221713 | 29 | _rst(user_RSTPin, 1) |
adhyyan | 0:7f603f221713 | 30 | |
adhyyan | 0:7f603f221713 | 31 | { |
adhyyan | 0:7f603f221713 | 32 | |
adhyyan | 0:7f603f221713 | 33 | //Get user settings |
adhyyan | 0:7f603f221713 | 34 | _i2cPortSpeed = i2cPortSpeed; |
adhyyan | 0:7f603f221713 | 35 | |
adhyyan | 0:7f603f221713 | 36 | #define MAX8U_MAX_SPEED 4000000 // 400 kHz |
adhyyan | 0:7f603f221713 | 37 | if(_i2cPortSpeed > MAX8U_MAX_SPEED) |
adhyyan | 0:7f603f221713 | 38 | { |
adhyyan | 0:7f603f221713 | 39 | _i2cPortSpeed = MAX8U_MAX_SPEED; |
adhyyan | 0:7f603f221713 | 40 | } |
adhyyan | 0:7f603f221713 | 41 | _i2cPort.frequency(_i2cPortSpeed); |
adhyyan | 0:7f603f221713 | 42 | } |
adhyyan | 0:7f603f221713 | 43 | |
adhyyan | 0:7f603f221713 | 44 | |
adhyyan | 0:7f603f221713 | 45 | bool MAX8U::begin(){ |
adhyyan | 0:7f603f221713 | 46 | //Configure the MAX8U for I2C communication |
adhyyan | 0:7f603f221713 | 47 | |
adhyyan | 0:7f603f221713 | 48 | _rst = 0; // Reset BNO080 |
adhyyan | 0:7f603f221713 | 49 | wait(.002f); // Min length not specified in datasheet? |
adhyyan | 0:7f603f221713 | 50 | _rst = 1; // Bring out of reset |
adhyyan | 0:7f603f221713 | 51 | |
adhyyan | 0:7f603f221713 | 52 | //TODO: wait for the GPS to boot. Couldnt find any pin in the data sheet which would be useful |
adhyyan | 0:7f603f221713 | 53 | wait(0.1f); //for now, just wait for some time |
adhyyan | 0:7f603f221713 | 54 | |
adhyyan | 0:7f603f221713 | 55 | if(checkVersion()) |
adhyyan | 0:7f603f221713 | 56 | { |
adhyyan | 0:7f603f221713 | 57 | #ifdef MAX8U_DEBUG |
adhyyan | 0:7f603f221713 | 58 | _debugPort->printf("MAX8U booted up"); |
adhyyan | 0:7f603f221713 | 59 | #endif |
adhyyan | 0:7f603f221713 | 60 | return true; |
adhyyan | 0:7f603f221713 | 61 | } |
adhyyan | 0:7f603f221713 | 62 | else |
adhyyan | 0:7f603f221713 | 63 | { |
adhyyan | 0:7f603f221713 | 64 | _debugPort->printf("MAX8U not detected!"); |
adhyyan | 0:7f603f221713 | 65 | return false; |
adhyyan | 0:7f603f221713 | 66 | } |
adhyyan | 0:7f603f221713 | 67 | } |
adhyyan | 0:7f603f221713 | 68 | |
adhyyan | 0:7f603f221713 | 69 | bool MAX8U::update() |
adhyyan | 0:7f603f221713 | 70 | { |
adhyyan | 0:7f603f221713 | 71 | bool gotAnyMessages = false; |
adhyyan | 0:7f603f221713 | 72 | |
adhyyan | 0:7f603f221713 | 73 | while(readNextMessage()) |
adhyyan | 0:7f603f221713 | 74 | { |
adhyyan | 0:7f603f221713 | 75 | processMessage(); |
adhyyan | 0:7f603f221713 | 76 | |
adhyyan | 0:7f603f221713 | 77 | gotAnyMessages = true; |
adhyyan | 0:7f603f221713 | 78 | } |
adhyyan | 0:7f603f221713 | 79 | |
adhyyan | 0:7f603f221713 | 80 | |
adhyyan | 0:7f603f221713 | 81 | return gotAnyMessages; |
adhyyan | 0:7f603f221713 | 82 | } |
adhyyan | 0:7f603f221713 | 83 | |
adhyyan | 0:7f603f221713 | 84 | bool MAX8U::configure() |
adhyyan | 0:7f603f221713 | 85 | { |
adhyyan | 0:7f603f221713 | 86 | // switch to UBX mode |
adhyyan | 0:7f603f221713 | 87 | if(!configureCommSettings()) |
adhyyan | 0:7f603f221713 | 88 | { |
adhyyan | 0:7f603f221713 | 89 | return false; |
adhyyan | 0:7f603f221713 | 90 | } |
adhyyan | 0:7f603f221713 | 91 | |
adhyyan | 0:7f603f221713 | 92 | // enable NAV messages |
adhyyan | 0:7f603f221713 | 93 | // latitude, longitude, and height |
adhyyan | 0:7f603f221713 | 94 | if(!setMessageEnabled(UBX_CLASS_NAV, UBX_NAV_POSLLH, true)) |
adhyyan | 0:7f603f221713 | 95 | { |
adhyyan | 0:7f603f221713 | 96 | return false; |
adhyyan | 0:7f603f221713 | 97 | } |
adhyyan | 0:7f603f221713 | 98 | |
adhyyan | 0:7f603f221713 | 99 | if(!setMessageEnabled(UBX_CLASS_NAV, UBX_NAV_SOL, true)) |
adhyyan | 0:7f603f221713 | 100 | { |
adhyyan | 0:7f603f221713 | 101 | return false; |
adhyyan | 0:7f603f221713 | 102 | } |
adhyyan | 0:7f603f221713 | 103 | |
adhyyan | 0:7f603f221713 | 104 | if(!setMessageEnabled(UBX_CLASS_NAV, UBX_NAV_TIMEUTC, true)) |
adhyyan | 0:7f603f221713 | 105 | { |
adhyyan | 0:7f603f221713 | 106 | return false; |
adhyyan | 0:7f603f221713 | 107 | } |
adhyyan | 0:7f603f221713 | 108 | |
adhyyan | 0:7f603f221713 | 109 | |
adhyyan | 0:7f603f221713 | 110 | if(!setMessageEnabled(UBX_CLASS_NAV, UBX_NAV_VELNED, true)) |
adhyyan | 0:7f603f221713 | 111 | { |
adhyyan | 0:7f603f221713 | 112 | return false; |
adhyyan | 0:7f603f221713 | 113 | } |
adhyyan | 0:7f603f221713 | 114 | |
adhyyan | 0:7f603f221713 | 115 | return saveSettings(); |
adhyyan | 0:7f603f221713 | 116 | |
adhyyan | 0:7f603f221713 | 117 | } |
adhyyan | 0:7f603f221713 | 118 | |
adhyyan | 0:7f603f221713 | 119 | bool MAX8U::setMessageEnabled(uint8_t messageClass, uint8_t messageID, bool enabled) |
adhyyan | 0:7f603f221713 | 120 | { |
adhyyan | 0:7f603f221713 | 121 | uint8_t data[3]; |
adhyyan | 0:7f603f221713 | 122 | |
adhyyan | 0:7f603f221713 | 123 | data[0] = messageClass; // byte 0: class |
adhyyan | 0:7f603f221713 | 124 | data[1] = messageID; // byte 1: ID |
adhyyan | 0:7f603f221713 | 125 | data[2] = static_cast<uint8_t>(enabled ? 1 : 0); // byte 2: rate |
adhyyan | 0:7f603f221713 | 126 | |
adhyyan | 0:7f603f221713 | 127 | if(!sendCommand(UBX_CLASS_CFG, UBX_CFG_MSG, data, sizeof(data))) |
adhyyan | 0:7f603f221713 | 128 | { |
adhyyan | 0:7f603f221713 | 129 | return false; |
adhyyan | 0:7f603f221713 | 130 | } |
adhyyan | 0:7f603f221713 | 131 | |
adhyyan | 0:7f603f221713 | 132 | return waitForACK(UBX_CLASS_CFG, UBX_CFG_MSG); |
adhyyan | 0:7f603f221713 | 133 | } |
adhyyan | 0:7f603f221713 | 134 | |
adhyyan | 0:7f603f221713 | 135 | MAX8U::AntennaPowerStatus MAX8U::antennaPowerStatus() { |
adhyyan | 0:7f603f221713 | 136 | sendCommand(UBX_CLASS_MON, UBX_MON_HW, nullptr, 0); |
adhyyan | 0:7f603f221713 | 137 | |
adhyyan | 0:7f603f221713 | 138 | if(!waitForMessage(UBX_CLASS_MON, UBX_MON_HW)) |
adhyyan | 0:7f603f221713 | 139 | { |
adhyyan | 0:7f603f221713 | 140 | return MAX8U::AntennaPowerStatus::NO_MESSAGE_RCVD; |
adhyyan | 0:7f603f221713 | 141 | } |
adhyyan | 0:7f603f221713 | 142 | |
adhyyan | 0:7f603f221713 | 143 | //else print out whether its on or off |
adhyyan | 0:7f603f221713 | 144 | MAX8U::AntennaPowerStatus powerStatus = AntennaPowerStatus (static_cast<uint8_t >(buffer[UBX_DATA_OFFSET + 21])); |
adhyyan | 0:7f603f221713 | 145 | return powerStatus; |
adhyyan | 0:7f603f221713 | 146 | } |
adhyyan | 0:7f603f221713 | 147 | |
adhyyan | 0:7f603f221713 | 148 | ssize_t MAX8U::readSatelliteInfo(MAX8U::SatelliteInfo *satelliteInfos, size_t infoLen) |
adhyyan | 0:7f603f221713 | 149 | { |
adhyyan | 0:7f603f221713 | 150 | sendCommand(UBX_CLASS_NAV, UBX_NAV_SAT, nullptr, 0); |
adhyyan | 0:7f603f221713 | 151 | |
adhyyan | 0:7f603f221713 | 152 | if(!waitForMessage(UBX_CLASS_NAV, UBX_NAV_SAT)) |
adhyyan | 0:7f603f221713 | 153 | { |
adhyyan | 0:7f603f221713 | 154 | return -1; |
adhyyan | 0:7f603f221713 | 155 | } |
adhyyan | 0:7f603f221713 | 156 | |
adhyyan | 0:7f603f221713 | 157 | uint8_t satellitesReturned = static_cast<uint8_t>(buffer[UBX_DATA_OFFSET + 5]); |
adhyyan | 0:7f603f221713 | 158 | |
adhyyan | 0:7f603f221713 | 159 | for(size_t i = 0; i < std::min(static_cast<size_t>(satellitesReturned), infoLen); i++) |
adhyyan | 0:7f603f221713 | 160 | { |
adhyyan | 0:7f603f221713 | 161 | // detect a buffer overrun in the case where more satellites were returned than could |
adhyyan | 0:7f603f221713 | 162 | // fit in the buffer |
adhyyan | 0:7f603f221713 | 163 | size_t flagOffset = UBX_DATA_OFFSET + 16 + 12*i; |
adhyyan | 0:7f603f221713 | 164 | if(flagOffset >= bufferMaxLen) |
adhyyan | 0:7f603f221713 | 165 | { |
adhyyan | 0:7f603f221713 | 166 | _debugPort->printf("Error: NAV-SAT message truncated by receive buffer size!\r\n"); |
adhyyan | 0:7f603f221713 | 167 | |
adhyyan | 0:7f603f221713 | 168 | // keep the part that was valid |
adhyyan | 0:7f603f221713 | 169 | return i; |
adhyyan | 0:7f603f221713 | 170 | } |
adhyyan | 0:7f603f221713 | 171 | |
adhyyan | 0:7f603f221713 | 172 | satelliteInfos[i].gnss = static_cast<GNSSID>(static_cast<uint8_t>(buffer[UBX_DATA_OFFSET + 8 + 12 * i])); |
adhyyan | 0:7f603f221713 | 173 | satelliteInfos[i].satelliteID = static_cast<uint8_t>(buffer[UBX_DATA_OFFSET + 9 + 12*i]); |
adhyyan | 0:7f603f221713 | 174 | satelliteInfos[i].signalStrength = static_cast<uint8_t>(buffer[UBX_DATA_OFFSET + 10 + 12*i]); |
adhyyan | 0:7f603f221713 | 175 | |
adhyyan | 0:7f603f221713 | 176 | uint32_t flag = readUnalignedValue<uint32_t>(buffer, flagOffset); |
adhyyan | 0:7f603f221713 | 177 | |
adhyyan | 0:7f603f221713 | 178 | satelliteInfos[i].signalQuality = (flag & 0x0007); |
adhyyan | 0:7f603f221713 | 179 | satelliteInfos[i].svUsed = (flag & (1<<3)); |
adhyyan | 0:7f603f221713 | 180 | |
adhyyan | 0:7f603f221713 | 181 | //satelliteInfos[i].elevation = static_cast<int8_t >(buffer[UBX_DATA_OFFSET]) |
adhyyan | 0:7f603f221713 | 182 | |
adhyyan | 0:7f603f221713 | 183 | #if MAX8U_DEBUG |
adhyyan | 0:7f603f221713 | 184 | _debugPort->printf("NAV_SAT Strength for %s %" PRIu8 ":: %" PRIu8 " dBHz; Quality: %" PRIu8 "\r\n", |
adhyyan | 0:7f603f221713 | 185 | satelliteInfos[i].getGNSSName(), satelliteInfos[i].satelliteID, |
adhyyan | 0:7f603f221713 | 186 | satelliteInfos[i].signalStrength, satelliteInfos[i].signalQuality); |
adhyyan | 0:7f603f221713 | 187 | #endif |
adhyyan | 0:7f603f221713 | 188 | } |
adhyyan | 0:7f603f221713 | 189 | |
adhyyan | 0:7f603f221713 | 190 | return satellitesReturned; |
adhyyan | 0:7f603f221713 | 191 | } |
adhyyan | 0:7f603f221713 | 192 | |
adhyyan | 0:7f603f221713 | 193 | |
adhyyan | 0:7f603f221713 | 194 | void MAX8U::processMessage() |
adhyyan | 0:7f603f221713 | 195 | { |
adhyyan | 0:7f603f221713 | 196 | if(buffer[UBX_BYTE_CLASS] == UBX_CLASS_NAV) |
adhyyan | 0:7f603f221713 | 197 | { |
adhyyan | 0:7f603f221713 | 198 | switch(buffer[UBX_BYTE_ID]) |
adhyyan | 0:7f603f221713 | 199 | { |
adhyyan | 0:7f603f221713 | 200 | case UBX_NAV_POSLLH: |
adhyyan | 0:7f603f221713 | 201 | processNAV_POSLLH(); |
adhyyan | 0:7f603f221713 | 202 | break; |
adhyyan | 0:7f603f221713 | 203 | case UBX_NAV_SOL: |
adhyyan | 0:7f603f221713 | 204 | processNAV_SOL(); |
adhyyan | 0:7f603f221713 | 205 | break; |
adhyyan | 0:7f603f221713 | 206 | case UBX_NAV_TIMEUTC: |
adhyyan | 0:7f603f221713 | 207 | processNAV_TIMEUTC(); |
adhyyan | 0:7f603f221713 | 208 | break; |
adhyyan | 0:7f603f221713 | 209 | case UBX_NAV_VELNED: |
adhyyan | 0:7f603f221713 | 210 | processNAV_VELNED(); |
adhyyan | 0:7f603f221713 | 211 | break; |
adhyyan | 0:7f603f221713 | 212 | } |
adhyyan | 0:7f603f221713 | 213 | |
adhyyan | 0:7f603f221713 | 214 | } |
adhyyan | 0:7f603f221713 | 215 | } |
adhyyan | 0:7f603f221713 | 216 | void MAX8U::processNAV_VELNED() { |
adhyyan | 0:7f603f221713 | 217 | northVel = readUnalignedValue<int32_t>(buffer, UBX_DATA_OFFSET + 4); |
adhyyan | 0:7f603f221713 | 218 | eastVel = readUnalignedValue<int32_t>(buffer, UBX_DATA_OFFSET + 8); |
adhyyan | 0:7f603f221713 | 219 | downVel = readUnalignedValue<int32_t>(buffer, UBX_DATA_OFFSET + 12); |
adhyyan | 0:7f603f221713 | 220 | speed3D = readUnalignedValue<uint32_t>(buffer, UBX_DATA_OFFSET + 16); |
adhyyan | 0:7f603f221713 | 221 | |
adhyyan | 0:7f603f221713 | 222 | #if MAX8U_DEBUG |
adhyyan | 0:7f603f221713 | 223 | _debugPort->printf("Got NAV_VELNED message. North Vel=%" PRIi32 ", East Vel=%" PRIi32 ", Down Vel=%" PRIi32 ", 3D Speed=%" PRIu32 "\r\n", |
adhyyan | 0:7f603f221713 | 224 | northVel, eastVel, downVel, speed3D); |
adhyyan | 0:7f603f221713 | 225 | #endif |
adhyyan | 0:7f603f221713 | 226 | } |
adhyyan | 0:7f603f221713 | 227 | |
adhyyan | 0:7f603f221713 | 228 | |
adhyyan | 0:7f603f221713 | 229 | void MAX8U::processNAV_POSLLH() |
adhyyan | 0:7f603f221713 | 230 | { |
adhyyan | 0:7f603f221713 | 231 | // read latitude and longitude |
adhyyan | 0:7f603f221713 | 232 | int32_t longitudeInt = readUnalignedValue<int32_t>(buffer, UBX_DATA_OFFSET + 4); |
adhyyan | 0:7f603f221713 | 233 | longitude = longitudeInt * 1e-7; |
adhyyan | 0:7f603f221713 | 234 | |
adhyyan | 0:7f603f221713 | 235 | int32_t latitudeInt = readUnalignedValue<int32_t>(buffer, UBX_DATA_OFFSET + 8); |
adhyyan | 0:7f603f221713 | 236 | latitude = latitudeInt * 1e-7; |
adhyyan | 0:7f603f221713 | 237 | |
adhyyan | 0:7f603f221713 | 238 | height = readUnalignedValue<int32_t>(buffer, UBX_DATA_OFFSET + 12)/(1000.0f); //height above ellipsoid |
adhyyan | 0:7f603f221713 | 239 | |
adhyyan | 0:7f603f221713 | 240 | #if MAX8U_DEBUG |
adhyyan | 0:7f603f221713 | 241 | _debugPort->printf("Got NAV_POSLLH message. Longitude=%.06f deg, Latitude=%.06f deg, Height=%.02f m\r\n", longitude, latitude, height); |
adhyyan | 0:7f603f221713 | 242 | #endif |
adhyyan | 0:7f603f221713 | 243 | } |
adhyyan | 0:7f603f221713 | 244 | |
adhyyan | 0:7f603f221713 | 245 | |
adhyyan | 0:7f603f221713 | 246 | void MAX8U::processNAV_SOL() |
adhyyan | 0:7f603f221713 | 247 | { |
adhyyan | 0:7f603f221713 | 248 | fixQuality = static_cast<GPSFix>(buffer[UBX_DATA_OFFSET + 10]); |
adhyyan | 0:7f603f221713 | 249 | |
adhyyan | 0:7f603f221713 | 250 | posAccuracy = readUnalignedValue<uint32_t>(buffer, UBX_DATA_OFFSET + 24) / 100.0f; |
adhyyan | 0:7f603f221713 | 251 | |
adhyyan | 0:7f603f221713 | 252 | numSatellites = static_cast<uint8_t>(buffer[UBX_DATA_OFFSET + 47]); |
adhyyan | 0:7f603f221713 | 253 | |
adhyyan | 0:7f603f221713 | 254 | #if MAX8U_DEBUG |
adhyyan | 0:7f603f221713 | 255 | _debugPort->printf("Got NAV_SOL message. Fix quality=%" PRIu8 ", Pos accuracy=%.02f m, Num satellites=%" PRIu8 "\r\n", |
adhyyan | 0:7f603f221713 | 256 | static_cast<uint8_t>(fixQuality), posAccuracy, numSatellites); |
adhyyan | 0:7f603f221713 | 257 | #endif |
adhyyan | 0:7f603f221713 | 258 | } |
adhyyan | 0:7f603f221713 | 259 | |
adhyyan | 0:7f603f221713 | 260 | void MAX8U::processNAV_TIMEUTC() |
adhyyan | 0:7f603f221713 | 261 | { |
adhyyan | 0:7f603f221713 | 262 | year = readUnalignedValue<uint16_t>(buffer, UBX_DATA_OFFSET + 12); |
adhyyan | 0:7f603f221713 | 263 | |
adhyyan | 0:7f603f221713 | 264 | month = static_cast<uint8_t>(buffer[UBX_DATA_OFFSET + 14]); |
adhyyan | 0:7f603f221713 | 265 | |
adhyyan | 0:7f603f221713 | 266 | day = static_cast<uint8_t>(buffer[UBX_DATA_OFFSET + 15]); |
adhyyan | 0:7f603f221713 | 267 | |
adhyyan | 0:7f603f221713 | 268 | hour = static_cast<uint8_t>(buffer[UBX_DATA_OFFSET + 16]); |
adhyyan | 0:7f603f221713 | 269 | |
adhyyan | 0:7f603f221713 | 270 | minute = static_cast<uint8_t>(buffer[UBX_DATA_OFFSET + 17]); |
adhyyan | 0:7f603f221713 | 271 | |
adhyyan | 0:7f603f221713 | 272 | second = static_cast<uint8_t>(buffer[UBX_DATA_OFFSET + 18]); |
adhyyan | 0:7f603f221713 | 273 | |
adhyyan | 0:7f603f221713 | 274 | #if MAX8U_DEBUG |
adhyyan | 0:7f603f221713 | 275 | _debugPort->printf("Got NAV_TIMEUTC message. year=%" PRIu16 ", month =%" PRIu8 ", day=%" PRIu8 |
adhyyan | 0:7f603f221713 | 276 | ", hour = %" PRIu8 ", min = %" PRIu8 ", sec = %" PRIu8 "\r\n", |
adhyyan | 0:7f603f221713 | 277 | year, month, day, hour, minute, second); |
adhyyan | 0:7f603f221713 | 278 | #endif |
adhyyan | 0:7f603f221713 | 279 | |
adhyyan | 0:7f603f221713 | 280 | } |
adhyyan | 0:7f603f221713 | 281 | |
adhyyan | 0:7f603f221713 | 282 | bool MAX8U::waitForMessage(uint8_t messageClass, uint8_t messageID, float timeout) |
adhyyan | 0:7f603f221713 | 283 | { |
adhyyan | 0:7f603f221713 | 284 | Timer timeoutTimer; |
adhyyan | 0:7f603f221713 | 285 | timeoutTimer.start(); |
adhyyan | 0:7f603f221713 | 286 | |
adhyyan | 0:7f603f221713 | 287 | while(timeoutTimer.read() <= timeout) |
adhyyan | 0:7f603f221713 | 288 | { |
adhyyan | 0:7f603f221713 | 289 | bool newMessageReceived = readNextMessage(); |
adhyyan | 0:7f603f221713 | 290 | |
adhyyan | 0:7f603f221713 | 291 | //We dont use TX Ready pin here, because it isn't configured when the GPS is first set up. |
adhyyan | 0:7f603f221713 | 292 | |
adhyyan | 0:7f603f221713 | 293 | if(!newMessageReceived){ |
adhyyan | 0:7f603f221713 | 294 | wait(0.001f); |
adhyyan | 0:7f603f221713 | 295 | continue; |
adhyyan | 0:7f603f221713 | 296 | } |
adhyyan | 0:7f603f221713 | 297 | |
adhyyan | 0:7f603f221713 | 298 | if(messageClass == buffer[UBX_BYTE_CLASS] && messageID == buffer[UBX_BYTE_ID]) |
adhyyan | 0:7f603f221713 | 299 | { |
adhyyan | 0:7f603f221713 | 300 | // found correct packet! |
adhyyan | 0:7f603f221713 | 301 | return true; |
adhyyan | 0:7f603f221713 | 302 | } |
adhyyan | 0:7f603f221713 | 303 | else |
adhyyan | 0:7f603f221713 | 304 | { |
adhyyan | 0:7f603f221713 | 305 | // other data message, send to proper channels |
adhyyan | 0:7f603f221713 | 306 | processMessage(); |
adhyyan | 0:7f603f221713 | 307 | } |
adhyyan | 0:7f603f221713 | 308 | |
adhyyan | 0:7f603f221713 | 309 | } |
adhyyan | 0:7f603f221713 | 310 | |
adhyyan | 0:7f603f221713 | 311 | _debugPort->printf("Timeout waiting for message 0x%02" PRIx8 " 0x%02" PRIx8 ".\r\n", messageClass, messageID); |
adhyyan | 0:7f603f221713 | 312 | return false; |
adhyyan | 0:7f603f221713 | 313 | } |
adhyyan | 0:7f603f221713 | 314 | |
adhyyan | 0:7f603f221713 | 315 | bool MAX8U::waitForACK(uint8_t sentMessageClass, uint8_t sentMessageID, float timeout) |
adhyyan | 0:7f603f221713 | 316 | { |
adhyyan | 0:7f603f221713 | 317 | // NOTE: we assume that we wait for an ACK before sending another message, so |
adhyyan | 0:7f603f221713 | 318 | // there will never be two ACKs in play at once |
adhyyan | 0:7f603f221713 | 319 | |
adhyyan | 0:7f603f221713 | 320 | if(!waitForMessage(UBX_CLASS_ACK, UBX_ACK_ACK)) |
adhyyan | 0:7f603f221713 | 321 | { |
adhyyan | 0:7f603f221713 | 322 | _debugPort->printf("Timeout waiting for ACK for message 0x%02" PRIx8 " 0x%02" PRIx8 "\r\n", |
adhyyan | 0:7f603f221713 | 323 | sentMessageClass, sentMessageID); |
adhyyan | 0:7f603f221713 | 324 | return false; |
adhyyan | 0:7f603f221713 | 325 | } |
adhyyan | 0:7f603f221713 | 326 | |
adhyyan | 0:7f603f221713 | 327 | // check the byte IDs |
adhyyan | 0:7f603f221713 | 328 | if(buffer[UBX_DATA_OFFSET] != sentMessageClass || buffer[UBX_DATA_OFFSET+1] != sentMessageID) |
adhyyan | 0:7f603f221713 | 329 | { |
adhyyan | 0:7f603f221713 | 330 | _debugPort->printf("Ack rcvd for wrong message\r\n"); |
adhyyan | 0:7f603f221713 | 331 | return false; |
adhyyan | 0:7f603f221713 | 332 | } |
adhyyan | 0:7f603f221713 | 333 | |
adhyyan | 0:7f603f221713 | 334 | |
adhyyan | 0:7f603f221713 | 335 | return true; |
adhyyan | 0:7f603f221713 | 336 | } |
adhyyan | 0:7f603f221713 | 337 | |
adhyyan | 0:7f603f221713 | 338 | bool MAX8U::configureCommSettings(){ |
adhyyan | 0:7f603f221713 | 339 | //Configure DDC(I2C) by writing |
adhyyan | 0:7f603f221713 | 340 | |
adhyyan | 0:7f603f221713 | 341 | //Configures the MAX8 to output in UBX format instead of NMEA format. |
adhyyan | 0:7f603f221713 | 342 | |
adhyyan | 0:7f603f221713 | 343 | /* |
adhyyan | 0:7f603f221713 | 344 | UBX-CFG-PRT Payload |
adhyyan | 0:7f603f221713 | 345 | 1 PortId = 0 |
adhyyan | 0:7f603f221713 | 346 | 1 reserved1 |
adhyyan | 0:7f603f221713 | 347 | 2 txReady |
adhyyan | 0:7f603f221713 | 348 | 4 mode - 7 address and 0 for write |
adhyyan | 0:7f603f221713 | 349 | 4 reserved - all 0s |
adhyyan | 0:7f603f221713 | 350 | 2 inProtoMask - keep 0th bit on, rest off |
adhyyan | 0:7f603f221713 | 351 | 2 outProtoMask - keep 0th bit on, rest off |
adhyyan | 0:7f603f221713 | 352 | 2 flags - all 0 |
adhyyan | 0:7f603f221713 | 353 | 2 reserved - all 0 |
adhyyan | 0:7f603f221713 | 354 | */ |
adhyyan | 0:7f603f221713 | 355 | |
adhyyan | 0:7f603f221713 | 356 | uint16_t dataLen = 20; |
adhyyan | 0:7f603f221713 | 357 | uint8_t data[20]; |
adhyyan | 0:7f603f221713 | 358 | data[0] = 0; //Port Id |
adhyyan | 0:7f603f221713 | 359 | data[1] = 0; //Reserved |
adhyyan | 0:7f603f221713 | 360 | |
adhyyan | 0:7f603f221713 | 361 | // disable TX ready |
adhyyan | 0:7f603f221713 | 362 | data[2] = 0; |
adhyyan | 0:7f603f221713 | 363 | data[3] = 0; |
adhyyan | 0:7f603f221713 | 364 | |
adhyyan | 0:7f603f221713 | 365 | data[4] = (_i2cAddress<<1); |
adhyyan | 0:7f603f221713 | 366 | data[5] = 0; |
adhyyan | 0:7f603f221713 | 367 | data[6] = 0; |
adhyyan | 0:7f603f221713 | 368 | data[7] = 0; |
adhyyan | 0:7f603f221713 | 369 | |
adhyyan | 0:7f603f221713 | 370 | data[8] = 0; |
adhyyan | 0:7f603f221713 | 371 | data[9] = 0; |
adhyyan | 0:7f603f221713 | 372 | data[10] = 0; |
adhyyan | 0:7f603f221713 | 373 | data[11] = 0; |
adhyyan | 0:7f603f221713 | 374 | |
adhyyan | 0:7f603f221713 | 375 | data[12] = 0x01; //enabling UBX mode for input |
adhyyan | 0:7f603f221713 | 376 | data[13] = 0; |
adhyyan | 0:7f603f221713 | 377 | |
adhyyan | 0:7f603f221713 | 378 | data[14] = 0x01; //enabling UBX mode for output |
adhyyan | 0:7f603f221713 | 379 | data[15] = 0; |
adhyyan | 0:7f603f221713 | 380 | |
adhyyan | 0:7f603f221713 | 381 | data[16] = 0; |
adhyyan | 0:7f603f221713 | 382 | data[17] = 0; |
adhyyan | 0:7f603f221713 | 383 | data[18] = 0; |
adhyyan | 0:7f603f221713 | 384 | data[19] = 0; |
adhyyan | 0:7f603f221713 | 385 | |
adhyyan | 0:7f603f221713 | 386 | |
adhyyan | 0:7f603f221713 | 387 | if(!sendCommand(UBX_CLASS_CFG, UBX_CFG_PRT, data, dataLen)) |
adhyyan | 0:7f603f221713 | 388 | { |
adhyyan | 0:7f603f221713 | 389 | return false; |
adhyyan | 0:7f603f221713 | 390 | } |
adhyyan | 0:7f603f221713 | 391 | |
adhyyan | 0:7f603f221713 | 392 | return waitForACK(UBX_CLASS_CFG, UBX_CFG_PRT); |
adhyyan | 0:7f603f221713 | 393 | } |
adhyyan | 0:7f603f221713 | 394 | |
adhyyan | 0:7f603f221713 | 395 | //send the header then the data to the Max8 on the default address 0x42 |
adhyyan | 0:7f603f221713 | 396 | //Returns false if sensor does not ACK |
adhyyan | 0:7f603f221713 | 397 | bool MAX8U::sendCommand(uint8_t messageClass, uint8_t messageID, uint8_t *data, uint16_t dataLen) |
adhyyan | 0:7f603f221713 | 398 | { |
adhyyan | 0:7f603f221713 | 399 | |
adhyyan | 0:7f603f221713 | 400 | //using UBX protocol |
adhyyan | 0:7f603f221713 | 401 | |
adhyyan | 0:7f603f221713 | 402 | // start the transaction and contact the IMU |
adhyyan | 0:7f603f221713 | 403 | _i2cPort.start(); |
adhyyan | 0:7f603f221713 | 404 | |
adhyyan | 0:7f603f221713 | 405 | // to indicate an i2c read, shift the 7 bit address up 1 bit and keep bit 0 as a 0 |
adhyyan | 0:7f603f221713 | 406 | int writeResult = _i2cPort.write(_i2cAddress << 1); |
adhyyan | 0:7f603f221713 | 407 | |
adhyyan | 0:7f603f221713 | 408 | if(writeResult != 1) |
adhyyan | 0:7f603f221713 | 409 | { |
adhyyan | 0:7f603f221713 | 410 | _debugPort->printf("MAX8U I2C write failed!\r\n"); |
adhyyan | 0:7f603f221713 | 411 | _i2cPort.stop(); |
adhyyan | 0:7f603f221713 | 412 | return false; |
adhyyan | 0:7f603f221713 | 413 | } |
adhyyan | 0:7f603f221713 | 414 | |
adhyyan | 0:7f603f221713 | 415 | #if MAX8U_DEBUG |
adhyyan | 0:7f603f221713 | 416 | _debugPort->printf("MAX8U I2C write acked!\r\n"); |
adhyyan | 0:7f603f221713 | 417 | #endif |
adhyyan | 0:7f603f221713 | 418 | |
adhyyan | 0:7f603f221713 | 419 | //compute checksum on header and data. Refer to datasheet |
adhyyan | 0:7f603f221713 | 420 | uint8_t chka = 0, chkb = 0; |
adhyyan | 0:7f603f221713 | 421 | |
adhyyan | 0:7f603f221713 | 422 | // add header portions to checksum; |
adhyyan | 0:7f603f221713 | 423 | chka += messageClass; |
adhyyan | 0:7f603f221713 | 424 | chkb += chka; |
adhyyan | 0:7f603f221713 | 425 | |
adhyyan | 0:7f603f221713 | 426 | chka += messageID; |
adhyyan | 0:7f603f221713 | 427 | chkb += chka; |
adhyyan | 0:7f603f221713 | 428 | |
adhyyan | 0:7f603f221713 | 429 | chka += dataLen & 0xFF; |
adhyyan | 0:7f603f221713 | 430 | chkb += chka; |
adhyyan | 0:7f603f221713 | 431 | |
adhyyan | 0:7f603f221713 | 432 | chka += dataLen >> 8; |
adhyyan | 0:7f603f221713 | 433 | chkb += chka; |
adhyyan | 0:7f603f221713 | 434 | |
adhyyan | 0:7f603f221713 | 435 | // add data to checksum |
adhyyan | 0:7f603f221713 | 436 | for(int i = 0; i < dataLen; i++){ |
adhyyan | 0:7f603f221713 | 437 | chka = chka + data[i]; |
adhyyan | 0:7f603f221713 | 438 | chkb = chkb + chka; |
adhyyan | 0:7f603f221713 | 439 | } |
adhyyan | 0:7f603f221713 | 440 | |
adhyyan | 0:7f603f221713 | 441 | //send the sync chars |
adhyyan | 0:7f603f221713 | 442 | _i2cPort.write(UBX_SYNC_CHAR_1); |
adhyyan | 0:7f603f221713 | 443 | _i2cPort.write(UBX_SYNC_CHAR_2); |
adhyyan | 0:7f603f221713 | 444 | |
adhyyan | 0:7f603f221713 | 445 | // send the header |
adhyyan | 0:7f603f221713 | 446 | _i2cPort.write(messageClass); |
adhyyan | 0:7f603f221713 | 447 | _i2cPort.write(messageID); |
adhyyan | 0:7f603f221713 | 448 | _i2cPort.write(dataLen & 0xFF); |
adhyyan | 0:7f603f221713 | 449 | _i2cPort.write(dataLen >> 8); |
adhyyan | 0:7f603f221713 | 450 | |
adhyyan | 0:7f603f221713 | 451 | |
adhyyan | 0:7f603f221713 | 452 | for(uint8_t i = 0; i < dataLen; i++){ |
adhyyan | 0:7f603f221713 | 453 | _i2cPort.write(data[i]); |
adhyyan | 0:7f603f221713 | 454 | } |
adhyyan | 0:7f603f221713 | 455 | |
adhyyan | 0:7f603f221713 | 456 | _i2cPort.write(chka); |
adhyyan | 0:7f603f221713 | 457 | _i2cPort.write(chkb); |
adhyyan | 0:7f603f221713 | 458 | |
adhyyan | 0:7f603f221713 | 459 | _i2cPort.stop(); |
adhyyan | 0:7f603f221713 | 460 | |
adhyyan | 0:7f603f221713 | 461 | #if MAX8U_DEBUG |
adhyyan | 0:7f603f221713 | 462 | _debugPort->printf("Sending: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8, |
adhyyan | 0:7f603f221713 | 463 | UBX_SYNC_CHAR_1, UBX_SYNC_CHAR_2, messageClass, messageID, dataLen & 0xFF, dataLen >> 8); |
adhyyan | 0:7f603f221713 | 464 | |
adhyyan | 0:7f603f221713 | 465 | for(uint16_t i = 0; i < dataLen; i++){ |
adhyyan | 0:7f603f221713 | 466 | _debugPort->printf(" %02" PRIx8, data[i]); |
adhyyan | 0:7f603f221713 | 467 | } |
adhyyan | 0:7f603f221713 | 468 | _debugPort->printf(" %02" PRIx8 " %02" PRIx8 "\r\n", chka, chkb); |
adhyyan | 0:7f603f221713 | 469 | #endif |
adhyyan | 0:7f603f221713 | 470 | |
adhyyan | 0:7f603f221713 | 471 | return true; |
adhyyan | 0:7f603f221713 | 472 | } |
adhyyan | 0:7f603f221713 | 473 | |
adhyyan | 0:7f603f221713 | 474 | bool MAX8U::saveSettings() |
adhyyan | 0:7f603f221713 | 475 | { |
adhyyan | 0:7f603f221713 | 476 | const size_t dataLen = 12; |
adhyyan | 0:7f603f221713 | 477 | uint8_t data[dataLen]; |
adhyyan | 0:7f603f221713 | 478 | |
adhyyan | 0:7f603f221713 | 479 | // don't clear any settings |
adhyyan | 0:7f603f221713 | 480 | memset(data, 0, 4); |
adhyyan | 0:7f603f221713 | 481 | |
adhyyan | 0:7f603f221713 | 482 | // save all settings |
adhyyan | 0:7f603f221713 | 483 | data[4] = 0b00011111; |
adhyyan | 0:7f603f221713 | 484 | data[5] = 0b00011111; |
adhyyan | 0:7f603f221713 | 485 | data[6] = 0; |
adhyyan | 0:7f603f221713 | 486 | data[7] = 0; |
adhyyan | 0:7f603f221713 | 487 | |
adhyyan | 0:7f603f221713 | 488 | memset(data + 8, 0, 4); |
adhyyan | 0:7f603f221713 | 489 | |
adhyyan | 0:7f603f221713 | 490 | if(!sendCommand(UBX_CLASS_CFG, UBX_CFG_CFG, data, dataLen)) |
adhyyan | 0:7f603f221713 | 491 | { |
adhyyan | 0:7f603f221713 | 492 | return false; |
adhyyan | 0:7f603f221713 | 493 | } |
adhyyan | 0:7f603f221713 | 494 | |
adhyyan | 0:7f603f221713 | 495 | return waitForACK(UBX_CLASS_CFG, UBX_CFG_CFG); |
adhyyan | 0:7f603f221713 | 496 | |
adhyyan | 0:7f603f221713 | 497 | } |
adhyyan | 0:7f603f221713 | 498 | |
adhyyan | 0:7f603f221713 | 499 | bool MAX8U::checkVersion() |
adhyyan | 0:7f603f221713 | 500 | { |
adhyyan | 0:7f603f221713 | 501 | sendCommand(UBX_CLASS_MON, UBX_MON_VER, nullptr, 0); |
adhyyan | 0:7f603f221713 | 502 | |
adhyyan | 0:7f603f221713 | 503 | if(!waitForMessage(UBX_CLASS_MON, UBX_MON_VER)) |
adhyyan | 0:7f603f221713 | 504 | { |
adhyyan | 0:7f603f221713 | 505 | return false; |
adhyyan | 0:7f603f221713 | 506 | } |
adhyyan | 0:7f603f221713 | 507 | |
adhyyan | 0:7f603f221713 | 508 | #if MAX8U_DEBUG |
adhyyan | 0:7f603f221713 | 509 | _debugPort->printf("MAXU8 Software Version: %s\r\n", buffer + UBX_DATA_OFFSET); |
adhyyan | 0:7f603f221713 | 510 | _debugPort->printf("MAXU8 Software Version: %s\r\n", buffer + UBX_DATA_OFFSET + 30); |
adhyyan | 0:7f603f221713 | 511 | |
adhyyan | 0:7f603f221713 | 512 | // print additional data |
adhyyan | 0:7f603f221713 | 513 | size_t numAdditionalLines = (currMessageLength - UBX_HEADER_FOOTER_LENGTH - 40) / 30; |
adhyyan | 0:7f603f221713 | 514 | |
adhyyan | 0:7f603f221713 | 515 | for(size_t line = 0; line < numAdditionalLines; line++) |
adhyyan | 0:7f603f221713 | 516 | { |
adhyyan | 0:7f603f221713 | 517 | _debugPort->printf("Extra Info: %s\r\n", buffer + UBX_DATA_OFFSET + 40 + 30*line); |
adhyyan | 0:7f603f221713 | 518 | } |
adhyyan | 0:7f603f221713 | 519 | |
adhyyan | 0:7f603f221713 | 520 | #endif |
adhyyan | 0:7f603f221713 | 521 | |
adhyyan | 0:7f603f221713 | 522 | return true; |
adhyyan | 0:7f603f221713 | 523 | } |
adhyyan | 0:7f603f221713 | 524 | |
adhyyan | 0:7f603f221713 | 525 | |
adhyyan | 0:7f603f221713 | 526 | void MAX8U::readGNSSConfig() { |
adhyyan | 0:7f603f221713 | 527 | sendCommand(UBX_CLASS_CFG, UBX_CFG_GNSS, nullptr, 0); |
adhyyan | 0:7f603f221713 | 528 | |
adhyyan | 0:7f603f221713 | 529 | if(!waitForMessage(UBX_CLASS_CFG, UBX_CFG_GNSS)){ |
adhyyan | 0:7f603f221713 | 530 | _debugPort->printf("NO MESSAGE RCVD for GNSS CFG message"); |
adhyyan | 0:7f603f221713 | 531 | return; |
adhyyan | 0:7f603f221713 | 532 | } |
adhyyan | 0:7f603f221713 | 533 | |
adhyyan | 0:7f603f221713 | 534 | uint8_t numTrkChHw = static_cast<uint8_t >(buffer[UBX_DATA_OFFSET + 1]); |
adhyyan | 0:7f603f221713 | 535 | uint8_t usedTracks = static_cast<uint8_t >(buffer[UBX_DATA_OFFSET + 2]); |
adhyyan | 0:7f603f221713 | 536 | uint8_t blocks = static_cast<uint8_t >(buffer[UBX_DATA_OFFSET + 3]); |
adhyyan | 0:7f603f221713 | 537 | _debugPort->printf("CHANNELS: %" PRIx8 " , USED: %" PRIx8 " , LEN: %" PRIx8 "\r\n", numTrkChHw, usedTracks, blocks); |
adhyyan | 0:7f603f221713 | 538 | for(int i = 0; i < blocks; i++){ |
adhyyan | 0:7f603f221713 | 539 | uint8_t gnssID = static_cast<uint8_t >(buffer[UBX_DATA_OFFSET + 4 + 8*i]); |
adhyyan | 0:7f603f221713 | 540 | uint32_t flag = static_cast<uint32_t >(buffer[UBX_DATA_OFFSET + 8 + 8*i]); |
adhyyan | 0:7f603f221713 | 541 | bool enabled = flag&1; |
adhyyan | 0:7f603f221713 | 542 | _debugPort->printf("GNSS ID: %" PRIx8 ", NAME: %s, ENABLED: %d \r\n", gnssID, GNSSNames[gnssID], enabled); |
adhyyan | 0:7f603f221713 | 543 | } |
adhyyan | 0:7f603f221713 | 544 | |
adhyyan | 0:7f603f221713 | 545 | } |
adhyyan | 0:7f603f221713 | 546 | |
adhyyan | 0:7f603f221713 | 547 | bool MAX8U::readNextMessage(){ |
adhyyan | 0:7f603f221713 | 548 | //keep reading the 0xff register until the buffer is ove |
adhyyan | 0:7f603f221713 | 549 | |
adhyyan | 0:7f603f221713 | 550 | int msgLen = readLen(); |
adhyyan | 0:7f603f221713 | 551 | if(msgLen == -1){ |
adhyyan | 0:7f603f221713 | 552 | _debugPort->printf("Didn't rcv ack from MAX8 when reading length\r\n"); |
adhyyan | 0:7f603f221713 | 553 | return false; |
adhyyan | 0:7f603f221713 | 554 | } |
adhyyan | 0:7f603f221713 | 555 | |
adhyyan | 0:7f603f221713 | 556 | if(msgLen == 0) |
adhyyan | 0:7f603f221713 | 557 | { |
adhyyan | 0:7f603f221713 | 558 | //nothing to do |
adhyyan | 0:7f603f221713 | 559 | return false; |
adhyyan | 0:7f603f221713 | 560 | } |
adhyyan | 0:7f603f221713 | 561 | |
adhyyan | 0:7f603f221713 | 562 | _i2cPort.start(); |
adhyyan | 0:7f603f221713 | 563 | int readResult = _i2cPort.write((_i2cAddress << 1) | 0x01); |
adhyyan | 0:7f603f221713 | 564 | |
adhyyan | 0:7f603f221713 | 565 | if(readResult != 1){ |
adhyyan | 0:7f603f221713 | 566 | _debugPort->printf("Didn't receive ack from MAX8\r\n"); |
adhyyan | 0:7f603f221713 | 567 | return false; |
adhyyan | 0:7f603f221713 | 568 | } |
adhyyan | 0:7f603f221713 | 569 | |
adhyyan | 0:7f603f221713 | 570 | // whether this is an NMEA or UBX sentence |
adhyyan | 0:7f603f221713 | 571 | bool isLastByte = false; |
adhyyan | 0:7f603f221713 | 572 | currMessageLength = 0; |
adhyyan | 0:7f603f221713 | 573 | int ubxMsgLen = 100000; // large value to stop loop exit condition, will read real value later |
adhyyan | 0:7f603f221713 | 574 | for(int i = 0; i < msgLen; i++) // for loop in case there's a data error and we don't detect the last byte |
adhyyan | 0:7f603f221713 | 575 | { |
adhyyan | 0:7f603f221713 | 576 | uint8_t incoming = static_cast<uint8_t >(_i2cPort.read(!isLastByte)); |
adhyyan | 0:7f603f221713 | 577 | if(i == 5 && !isNMEASentence){ |
adhyyan | 0:7f603f221713 | 578 | //read length and change that to msg length |
adhyyan | 0:7f603f221713 | 579 | ubxMsgLen = (static_cast<uint16_t>(buffer[i] << 8) | buffer[i-1]) + 8; |
adhyyan | 0:7f603f221713 | 580 | //non-payload body of a ubx message is 8 |
adhyyan | 0:7f603f221713 | 581 | |
adhyyan | 0:7f603f221713 | 582 | } |
adhyyan | 0:7f603f221713 | 583 | |
adhyyan | 0:7f603f221713 | 584 | if(i == 0) |
adhyyan | 0:7f603f221713 | 585 | { |
adhyyan | 0:7f603f221713 | 586 | if(incoming == NMEA_MESSAGE_START_CHAR) |
adhyyan | 0:7f603f221713 | 587 | { |
adhyyan | 0:7f603f221713 | 588 | // NMEA sentences start with a dollars sign |
adhyyan | 0:7f603f221713 | 589 | isNMEASentence = true; |
adhyyan | 0:7f603f221713 | 590 | } |
adhyyan | 0:7f603f221713 | 591 | else if(incoming == UBX_MESSAGE_START_CHAR) |
adhyyan | 0:7f603f221713 | 592 | { |
adhyyan | 0:7f603f221713 | 593 | // UBX sentences start with a 0xB5 |
adhyyan | 0:7f603f221713 | 594 | isNMEASentence = false; |
adhyyan | 0:7f603f221713 | 595 | } |
adhyyan | 0:7f603f221713 | 596 | else if(incoming == 0xFF) |
adhyyan | 0:7f603f221713 | 597 | { |
adhyyan | 0:7f603f221713 | 598 | _debugPort->printf("Message Length > 0, although buffer is empty\r\n"); |
adhyyan | 0:7f603f221713 | 599 | }else{ |
adhyyan | 0:7f603f221713 | 600 | _debugPort->printf("Unknown first character \r\n"); |
adhyyan | 0:7f603f221713 | 601 | } |
adhyyan | 0:7f603f221713 | 602 | |
adhyyan | 0:7f603f221713 | 603 | } |
adhyyan | 0:7f603f221713 | 604 | |
adhyyan | 0:7f603f221713 | 605 | if(i < bufferMaxLen){ |
adhyyan | 0:7f603f221713 | 606 | buffer[i] = incoming; |
adhyyan | 0:7f603f221713 | 607 | ++currMessageLength; |
adhyyan | 0:7f603f221713 | 608 | } |
adhyyan | 0:7f603f221713 | 609 | |
adhyyan | 0:7f603f221713 | 610 | if(isLastByte) |
adhyyan | 0:7f603f221713 | 611 | { |
adhyyan | 0:7f603f221713 | 612 | break; |
adhyyan | 0:7f603f221713 | 613 | } |
adhyyan | 0:7f603f221713 | 614 | |
adhyyan | 0:7f603f221713 | 615 | // post-receive actions |
adhyyan | 0:7f603f221713 | 616 | |
adhyyan | 0:7f603f221713 | 617 | // if it's an NMEA sentence, there is a CRLF at the end |
adhyyan | 0:7f603f221713 | 618 | // if it's an UBX sentence, there is a length passed before the payload |
adhyyan | 0:7f603f221713 | 619 | if((isNMEASentence && incoming == '\r') || (!isNMEASentence && i == ubxMsgLen-2)) |
adhyyan | 0:7f603f221713 | 620 | { |
adhyyan | 0:7f603f221713 | 621 | isLastByte = true; |
adhyyan | 0:7f603f221713 | 622 | } |
adhyyan | 0:7f603f221713 | 623 | } |
adhyyan | 0:7f603f221713 | 624 | |
adhyyan | 0:7f603f221713 | 625 | // add null terminator |
adhyyan | 0:7f603f221713 | 626 | buffer[currMessageLength] = 0; |
adhyyan | 0:7f603f221713 | 627 | |
adhyyan | 0:7f603f221713 | 628 | _i2cPort.stop(); |
adhyyan | 0:7f603f221713 | 629 | |
adhyyan | 0:7f603f221713 | 630 | |
adhyyan | 0:7f603f221713 | 631 | #if MAX8U_DEBUG |
adhyyan | 0:7f603f221713 | 632 | _debugPort->printf("Read stream of MAX8U: "); |
adhyyan | 0:7f603f221713 | 633 | for(uint16_t i = 0; i < currMessageLength; i++){ |
adhyyan | 0:7f603f221713 | 634 | _debugPort->printf("%02" PRIx8, buffer[i]); |
adhyyan | 0:7f603f221713 | 635 | } |
adhyyan | 0:7f603f221713 | 636 | _debugPort->printf(";\r\n"); |
adhyyan | 0:7f603f221713 | 637 | #endif |
adhyyan | 0:7f603f221713 | 638 | |
adhyyan | 0:7f603f221713 | 639 | if(!isNMEASentence) |
adhyyan | 0:7f603f221713 | 640 | { |
adhyyan | 0:7f603f221713 | 641 | uint8_t chka = 0, chkb = 0; |
adhyyan | 0:7f603f221713 | 642 | for(uint16_t i = 2; i < currMessageLength-2; i++) |
adhyyan | 0:7f603f221713 | 643 | { |
adhyyan | 0:7f603f221713 | 644 | chka += buffer[i]; |
adhyyan | 0:7f603f221713 | 645 | chkb += chka; |
adhyyan | 0:7f603f221713 | 646 | } |
adhyyan | 0:7f603f221713 | 647 | |
adhyyan | 0:7f603f221713 | 648 | if((chka != buffer[currMessageLength-2]) || (chkb != buffer[currMessageLength-1])) |
adhyyan | 0:7f603f221713 | 649 | { |
adhyyan | 0:7f603f221713 | 650 | _debugPort->printf("Checksums for UBX message don't match!\r\n"); |
adhyyan | 0:7f603f221713 | 651 | return false; |
adhyyan | 0:7f603f221713 | 652 | } |
adhyyan | 0:7f603f221713 | 653 | } |
adhyyan | 0:7f603f221713 | 654 | |
adhyyan | 0:7f603f221713 | 655 | return true; |
adhyyan | 0:7f603f221713 | 656 | |
adhyyan | 0:7f603f221713 | 657 | } |
adhyyan | 0:7f603f221713 | 658 | |
adhyyan | 0:7f603f221713 | 659 | |
adhyyan | 0:7f603f221713 | 660 | int32_t MAX8U::readLen(){ |
adhyyan | 0:7f603f221713 | 661 | |
adhyyan | 0:7f603f221713 | 662 | _i2cPort.start(); |
adhyyan | 0:7f603f221713 | 663 | int i2cStatus = _i2cPort.write((_i2cAddress << 1) | 0x00); |
adhyyan | 0:7f603f221713 | 664 | if(i2cStatus != 1) |
adhyyan | 0:7f603f221713 | 665 | return -1; |
adhyyan | 0:7f603f221713 | 666 | _i2cPort.write(0xFD); |
adhyyan | 0:7f603f221713 | 667 | |
adhyyan | 0:7f603f221713 | 668 | |
adhyyan | 0:7f603f221713 | 669 | _i2cPort.start(); |
adhyyan | 0:7f603f221713 | 670 | i2cStatus = _i2cPort.write((_i2cAddress << 1) | 0x01); |
adhyyan | 0:7f603f221713 | 671 | if(i2cStatus != 1) |
adhyyan | 0:7f603f221713 | 672 | return -1; |
adhyyan | 0:7f603f221713 | 673 | |
adhyyan | 0:7f603f221713 | 674 | uint8_t highByte = static_cast<uint8_t>(_i2cPort.read(true)); |
adhyyan | 0:7f603f221713 | 675 | uint8_t lowByte = static_cast<uint8_t>(_i2cPort.read(false)); |
adhyyan | 0:7f603f221713 | 676 | |
adhyyan | 0:7f603f221713 | 677 | _i2cPort.stop(); |
adhyyan | 0:7f603f221713 | 678 | |
adhyyan | 0:7f603f221713 | 679 | return (static_cast<uint16_t>(highByte << 8) | lowByte); |
adhyyan | 0:7f603f221713 | 680 | } |
adhyyan | 0:7f603f221713 | 681 | |
adhyyan | 0:7f603f221713 | 682 |