├── .gitattributes ├── .gitignore ├── LICENSE.md ├── README.md ├── examples ├── Example1-BasicReadings │ └── Example1-BasicReadings.ino ├── Example2-TinyGPS │ └── Example2-TinyGPS.ino ├── Example3-MoreGPSInfo │ └── Example3-MoreGPSInfo.ino ├── Example4-LibraryOptions │ └── Example4-LibraryOptions.ino └── Example5-ConfigureGPS │ └── Example5-ConfigureGPS.ino ├── externs.h ├── keywords.txt ├── library.properties ├── main.cpp └── src ├── SparkFun_I2C_GPS_Arduino_Library.cpp └── SparkFun_I2C_GPS_Arduino_Library.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | SparkFun License Information 2 | ============================ 3 | 4 | SparkFun uses two different licenses for our files — one for hardware and one for code. 5 | 6 | Hardware 7 | --------- 8 | 9 | **SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).** 10 | 11 | Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode). 12 | 13 | You are free to: 14 | 15 | Share — copy and redistribute the material in any medium or format 16 | Adapt — remix, transform, and build upon the material 17 | for any purpose, even commercially. 18 | The licensor cannot revoke these freedoms as long as you follow the license terms. 19 | Under the following terms: 20 | 21 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 22 | ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 23 | No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. 24 | Notices: 25 | 26 | You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation. 27 | No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material. 28 | 29 | 30 | Code 31 | -------- 32 | 33 | **SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).** 34 | 35 | The MIT License (MIT) 36 | 37 | Copyright (c) 2016 SparkFun Electronics 38 | 39 | Permission is hereby granted, free of charge, to any person obtaining a copy 40 | of this software and associated documentation files (the "Software"), to deal 41 | in the Software without restriction, including without limitation the rights 42 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 43 | copies of the Software, and to permit persons to whom the Software is 44 | furnished to do so, subject to the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be included in all 47 | copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 53 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 54 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 55 | SOFTWARE. 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun MediaTek I2C Interface Library 2 | =========================================================== 3 | 4 | [![SparkFun GPS Breakout - XA1110 (Qwiic)](https://cdn.sparkfun.com//assets/parts/1/2/3/4/0/14414-SparkFun_GPS_Breakout_-_XA1110__Qwiic_-01.jpg)](https://www.sparkfun.com/products/14414) 5 | 6 | [*SparkFun GPS Breakout - XA1110 (Qwiic) (SEN-14414)*](https://www.sparkfun.com/products/14414) 7 | 8 | The Qwiic GPS uses the Titan X1 GPS module with special I2C firmware. This library talks to the GPS module over I2C. 9 | 10 | For Arduino we recommend using the [TinyGPS++ library](https://github.com/mikalhart/TinyGPSPlus) in addition to this library. Works like a champ together. 11 | 12 | For mBed-OS use [codygrays port of the TinyGPS++ library](https://github.com/codygray/TinyGPSPlus/tree/universal) instead. 13 | 14 | Library written by Nathan Seidle ([SparkFun](http://www.sparkfun.com)). 15 | 16 | Repository Contents 17 | ------------------- 18 | 19 | * **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. 20 | * **/src** - Source files for the library (.cpp, .h). These are hybridized versions that work under Arduino and mBed as well. 21 | * **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE. 22 | * **library.properties** - General library properties for the Arduino package manager. 23 | * **main.cpp** - Basic example code for mBed-OS. 24 | * **externs.h** - Needed by mBed-OS to let .h and .cpp files use the same I2C and Serial definition. 25 | 26 | Documentation 27 | -------------- 28 | 29 | * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. 30 | * **[Product Repository](https://github.com/sparkfunx/Qwiic_GPS-TitanX1)** - Main repository (including hardware files) for the Titan X1 Qwiic breakout board. 31 | 32 | License Information 33 | ------------------- 34 | 35 | This product is _**open source**_! 36 | 37 | Various bits of the code have different licenses applied. Anything SparkFun wrote is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round! Anything Maxim wrote has its own license. Anything that was co-writing with Peter Jansen is BSD. 38 | 39 | Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license. 40 | 41 | Distributed as-is; no warranty is given. 42 | 43 | - Your friends at SparkFun. 44 | -------------------------------------------------------------------------------- /examples/Example1-BasicReadings/Example1-BasicReadings.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Reading the raw NMEA sentences from the Qwiic GPS module over I2C 3 | By: Nathan Seidle 4 | SparkFun Electronics 5 | Date: April 12th, 2017 6 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 7 | 8 | This grabs the incoming NMEA sentences like GNGGA and GNRMC over I2C and outputs them to the serial 9 | monitor at 115200bps. 10 | 11 | We've included the library with this example so that you can get started immediately. For the other 12 | examples you'll need to install the SparkFun I2C GPS Arduino library from the Library manager. 13 | 14 | Hardware Connections: 15 | Attach a Qwiic shield to your RedBoard or Uno. 16 | Plug the Qwiic sensor into any port. 17 | PORT.print it out at 115200 baud to serial monitor. 18 | */ 19 | 20 | #include "SparkFun_I2C_GPS_Arduino_Library.h" //Use Library Manager or download here: https://github.com/sparkfun/SparkFun_I2C_GPS_Arduino_Library 21 | I2CGPS myI2CGPS; //Hook object to the library 22 | 23 | #define PORT Serial 24 | //#define PORT SerialUSB 25 | 26 | void setup() 27 | { 28 | PORT.begin(115200); 29 | PORT.println("GTOP Read Example"); 30 | 31 | while (myI2CGPS.begin() == false) 32 | { 33 | PORT.println("Module failed to respond. Please check wiring."); 34 | delay(500); 35 | } 36 | PORT.println("GPS module found!"); 37 | } 38 | 39 | void loop() 40 | { 41 | while (myI2CGPS.available()) //available() returns the number of new bytes available from the GPS module 42 | { 43 | byte incoming = myI2CGPS.read(); //Read the latest byte from Qwiic GPS 44 | 45 | if(incoming == '$') PORT.println(); //Break the sentences onto new lines 46 | PORT.write(incoming); //Print this character 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /examples/Example2-TinyGPS/Example2-TinyGPS.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Reading Lat/Long from the Qwiic GPS module over I2C 3 | By: Nathan Seidle 4 | SparkFun Electronics 5 | Date: April 12th, 2017 6 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 7 | 8 | This example shows date, time and location. 9 | 10 | You will need two libraries: 11 | 1) Use library manager to search for and install: 'SparkFun I2C GPS Arduino Library' 12 | 2) Download and install the zip library from https://github.com/mikalhart/TinyGPSPlus 13 | 14 | The TitanX1 has a buffer of approximately 1,000 NMEA characters. If you don't poll the module 15 | for a few seconds this buffer will fill up. The first time you read from the GPS module you will 16 | receive this large buffer and may take up to 800ms to clear out the contents. After that it will 17 | take approximately 20ms to read the contents of the I2C buffer from the module. 18 | 19 | Hardware Connections: 20 | Attach a Qwiic shield to your RedBoard or Uno. 21 | Plug the Qwiic sensor into any port. 22 | Serial.print it out at 115200 baud to serial monitor. 23 | */ 24 | 25 | #include //Use Library Manager or download here: https://github.com/sparkfun/SparkFun_I2C_GPS_Arduino_Library 26 | I2CGPS myI2CGPS; //Hook object to the library 27 | 28 | #include //From: https://github.com/mikalhart/TinyGPSPlus 29 | TinyGPSPlus gps; //Declare gps object 30 | 31 | void setup() 32 | { 33 | Serial.begin(115200); 34 | Serial.println("GTOP Read Example"); 35 | 36 | if (myI2CGPS.begin() == false) 37 | { 38 | Serial.println("Module failed to respond. Please check wiring."); 39 | while (1); //Freeze! 40 | } 41 | Serial.println("GPS module found!"); 42 | } 43 | 44 | void loop() 45 | { 46 | while (myI2CGPS.available()) //available() returns the number of new bytes available from the GPS module 47 | { 48 | gps.encode(myI2CGPS.read()); //Feed the GPS parser 49 | } 50 | 51 | if (gps.time.isUpdated()) //Check to see if new GPS info is available 52 | { 53 | displayInfo(); 54 | } 55 | } 56 | 57 | //Display new GPS info 58 | void displayInfo() 59 | { 60 | //We have new GPS data to deal with! 61 | Serial.println(); 62 | 63 | if (gps.time.isValid()) 64 | { 65 | Serial.print(F("Date: ")); 66 | Serial.print(gps.date.month()); 67 | Serial.print(F("/")); 68 | Serial.print(gps.date.day()); 69 | Serial.print(F("/")); 70 | Serial.print(gps.date.year()); 71 | 72 | Serial.print((" Time: ")); 73 | if (gps.time.hour() < 10) Serial.print(F("0")); 74 | Serial.print(gps.time.hour()); 75 | Serial.print(F(":")); 76 | if (gps.time.minute() < 10) Serial.print(F("0")); 77 | Serial.print(gps.time.minute()); 78 | Serial.print(F(":")); 79 | if (gps.time.second() < 10) Serial.print(F("0")); 80 | Serial.print(gps.time.second()); 81 | 82 | Serial.println(); //Done printing time 83 | } 84 | else 85 | { 86 | Serial.println(F("Time not yet valid")); 87 | } 88 | 89 | if (gps.location.isValid()) 90 | { 91 | Serial.print("Location: "); 92 | Serial.print(gps.location.lat(), 6); 93 | Serial.print(F(", ")); 94 | Serial.print(gps.location.lng(), 6); 95 | Serial.println(); 96 | } 97 | else 98 | { 99 | Serial.println(F("Location not yet valid")); 100 | } 101 | } 102 | 103 | 104 | -------------------------------------------------------------------------------- /examples/Example3-MoreGPSInfo/Example3-MoreGPSInfo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Display Lat/Long, Altitude, SIV and HDOP on the SparkFun Qwiic GPS module 3 | By: Nathan Seidle 4 | SparkFun Electronics 5 | Date: April 12th, 2017 6 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 7 | 8 | This example shows the regular info as well as Altitude, SIV, and HDOP. 9 | 10 | Hardware Connections: 11 | Attach a Qwiic shield to your RedBoard or Uno. 12 | Plug the Qwiic sensor into any port. 13 | Serial.print it out at 115200 baud to serial monitor. 14 | */ 15 | 16 | #include //Use Library Manager or download here: https://github.com/sparkfun/SparkFun_I2C_GPS_Arduino_Library 17 | I2CGPS myI2CGPS; //Hook object to the library 18 | 19 | #include //From: https://github.com/mikalhart/TinyGPSPlus 20 | TinyGPSPlus gps; //Declare gps object 21 | 22 | void setup() 23 | { 24 | Serial.begin(115200); 25 | Serial.println("GPS Read Example"); 26 | 27 | if (myI2CGPS.begin() == false) 28 | { 29 | Serial.println("Module failed to respond. Please check wiring."); 30 | while (1); //Freeze! 31 | } 32 | Serial.println("GPS module found!"); 33 | } 34 | 35 | void loop() 36 | { 37 | while (myI2CGPS.available()) //available() returns the number of new bytes available from the GPS module 38 | { 39 | gps.encode(myI2CGPS.read()); //Feed the GPS parser 40 | } 41 | 42 | if (gps.time.isUpdated()) //Check to see if new GPS info is available 43 | { 44 | displayInfo(); 45 | } 46 | } 47 | 48 | void displayInfo() 49 | { 50 | //We have new GPS data to deal with! 51 | Serial.println(); 52 | 53 | if (gps.time.isValid()) 54 | { 55 | Serial.print(F("Date: ")); 56 | Serial.print(gps.date.month()); 57 | Serial.print(F("/")); 58 | Serial.print(gps.date.day()); 59 | Serial.print(F("/")); 60 | Serial.print(gps.date.year()); 61 | 62 | Serial.print((" Time: ")); 63 | if (gps.time.hour() < 10) Serial.print(F("0")); 64 | Serial.print(gps.time.hour()); 65 | Serial.print(F(":")); 66 | if (gps.time.minute() < 10) Serial.print(F("0")); 67 | Serial.print(gps.time.minute()); 68 | Serial.print(F(":")); 69 | if (gps.time.second() < 10) Serial.print(F("0")); 70 | Serial.print(gps.time.second()); 71 | 72 | Serial.println(); //Done printing time 73 | } 74 | else 75 | { 76 | Serial.println(F("Time not yet valid")); 77 | } 78 | 79 | if (gps.location.isValid()) 80 | { 81 | Serial.print("Location: "); 82 | Serial.print(gps.location.lat(), 6); 83 | Serial.print(F(", ")); 84 | Serial.print(gps.location.lng(), 6); 85 | Serial.println(); 86 | } 87 | else 88 | { 89 | Serial.println(F("Location not yet valid")); 90 | } 91 | 92 | if (gps.altitude.isValid()) 93 | { 94 | Serial.print(F("Altitude Meters:")); 95 | Serial.print(gps.altitude.meters()); 96 | Serial.print(F(" Feet:")); 97 | Serial.print(gps.altitude.feet()); 98 | } 99 | 100 | if (gps.satellites.isValid()) 101 | { 102 | Serial.print(F(" Satellites in View:")); 103 | Serial.print(gps.satellites.value()); 104 | } 105 | 106 | if (gps.hdop.isValid()) 107 | { 108 | Serial.print(F(" HDOP:")); 109 | Serial.print(gps.hdop.value()/100.0, 2); //TinyGPS reports DOPs in 100ths 110 | } 111 | 112 | Serial.println(); //Done printing alt, siv, hdop 113 | } 114 | -------------------------------------------------------------------------------- /examples/Example4-LibraryOptions/Example4-LibraryOptions.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Showing additional .begin() options for the Qwiic GPS module library 3 | By: Nathan Seidle 4 | SparkFun Electronics 5 | Date: April 12th, 2017 6 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 7 | 8 | This example shows how to run library at 400kHz and on different Wire ports (like Teensy). 9 | 10 | Some platforms have multiple Wire ports. The library accepts these in .begin(). For example: 11 | myI2CGPS.begin(Wire2, 400000) will tell libaray to communicate over Wire2 port at 400kHz fast I2C 12 | 13 | Hardware Connections: 14 | Attach a Qwiic shield to your RedBoard or Uno. 15 | Plug the Qwiic sensor into any port. 16 | Serial.print it out at 115200 baud to serial monitor. 17 | */ 18 | 19 | #include //Use Library Manager or download here: https://github.com/sparkfun/SparkFun_I2C_GPS_Arduino_Library 20 | I2CGPS myI2CGPS; //Hook object to the library 21 | 22 | #include //From: https://github.com/mikalhart/TinyGPSPlus 23 | TinyGPSPlus gps; //Declare gps object 24 | 25 | void setup() 26 | { 27 | Serial.begin(115200); 28 | Serial.println("GPS Read Example"); 29 | 30 | //Use Wire as our I2C port. Wire1, Wire2, etc are allowed. Wire is default. 31 | //Use fast 400kHz I2C. 100kHz is default 32 | if (myI2CGPS.begin(Wire, 400000) == false) 33 | { 34 | Serial.println("Module failed to respond. Please check wiring."); 35 | while (1); //Freeze! 36 | } 37 | Serial.println("GPS module found!"); 38 | 39 | myI2CGPS.enableDebugging(Serial); //Turn on printing of GPS strings over the Serial port. SerialUSB, etc are allowed 40 | //But you must do a SerialUSB.begin(9600) or whatever within this setup()s. Library cannot do .begin() for Streams. 41 | 42 | //myI2CGPS.enableDebugging(SerialUSB); //Uncomment if you're using USB for debug messages 43 | //SerialUSB.begin(57600); //Uncomment if you're using USB for debug messages 44 | 45 | //myI2CGPS.disableDebugging(); //Turn off printing of GPS strings 46 | } 47 | 48 | void loop() 49 | { 50 | while (myI2CGPS.available()) //available() returns the number of new bytes available from the GPS module 51 | { 52 | gps.encode(myI2CGPS.read()); //Feed the GPS parser 53 | } 54 | 55 | if (gps.time.isUpdated()) //Check to see if new GPS info is available 56 | { 57 | displayInfo(); 58 | } 59 | } 60 | 61 | void displayInfo() 62 | { 63 | //We have new GPS data to deal with! 64 | Serial.println(); 65 | 66 | if (gps.time.isValid()) 67 | { 68 | Serial.print(F("Date: ")); 69 | Serial.print(gps.date.month()); 70 | Serial.print(F("/")); 71 | Serial.print(gps.date.day()); 72 | Serial.print(F("/")); 73 | Serial.print(gps.date.year()); 74 | 75 | Serial.print((" Time: ")); 76 | if (gps.time.hour() < 10) Serial.print(F("0")); 77 | Serial.print(gps.time.hour()); 78 | Serial.print(F(":")); 79 | if (gps.time.minute() < 10) Serial.print(F("0")); 80 | Serial.print(gps.time.minute()); 81 | Serial.print(F(":")); 82 | if (gps.time.second() < 10) Serial.print(F("0")); 83 | Serial.print(gps.time.second()); 84 | 85 | Serial.println(); //Done printing time 86 | } 87 | else 88 | { 89 | Serial.println(F("Time not yet valid")); 90 | } 91 | 92 | if (gps.location.isValid()) 93 | { 94 | Serial.print("Location: "); 95 | Serial.print(gps.location.lat(), 6); 96 | Serial.print(F(", ")); 97 | Serial.print(gps.location.lng(), 6); 98 | Serial.println(); 99 | } 100 | else 101 | { 102 | Serial.println(F("Location not yet valid")); 103 | } 104 | 105 | if (gps.altitude.isValid()) 106 | { 107 | Serial.print(F("Altitude Meters:")); 108 | Serial.print(gps.altitude.meters()); 109 | Serial.print(F(" Feet:")); 110 | Serial.print(gps.altitude.feet()); 111 | } 112 | 113 | if (gps.satellites.isValid()) 114 | { 115 | Serial.print(F(" Satellites in View:")); 116 | Serial.print(gps.satellites.value()); 117 | } 118 | 119 | if (gps.hdop.isValid()) 120 | { 121 | Serial.print(F(" HDOP:")); 122 | Serial.print(gps.hdop.value()); 123 | } 124 | 125 | Serial.println(); //Done printing alt, siv, hdop 126 | } 127 | -------------------------------------------------------------------------------- /examples/Example5-ConfigureGPS/Example5-ConfigureGPS.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Configure the Qwiic GPS module by sending PMTK packets 3 | By: Nathan Seidle, Owen Lyke 4 | SparkFun Electronics 5 | Date: April 12th, 2017 6 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 7 | 8 | Send the 'm' character to view the menu of options. 9 | 10 | This example shows how to configure the module including: 11 | Update rate to 1 or 10Hz (packet# 220) 12 | Enable/disable sentences (314) 13 | Pulse-per-second LED (285) 14 | Set Balloon mode (80km limit) (886) 15 | Set baud rate (251) 16 | Enable DGPS/SBAS 17 | Reset to factory defaults (104) 18 | 19 | For more information see the MTK NMEA Packet datasheet. 20 | 21 | Note that these settings are stored in battery backed memory and will be retained for 22 | approximately 15 days without power. 23 | 24 | This example has been updated to include limited support for the new firmware (5.x.x) that 25 | comes on the new modules. Use the techniques in this example along with the AirPrime software manual 26 | (https://cdn.sparkfun.com/assets/b/c/4/4/5/AirPrime_XM_XA_Series_Software_User_Guide_r3.pdf) 27 | to completely customize how the GPS module is set up 28 | 29 | Hardware Connections: 30 | Attach a Qwiic shield to your RedBoard or Uno. 31 | Plug the Qwiic sensor into any port. 32 | Serial.print it out at 115200 baud to serial monitor. 33 | */ 34 | 35 | #include //Use Library Manager or download here: https://github.com/sparkfun/SparkFun_I2C_GPS_Arduino_Library 36 | I2CGPS myI2CGPS; //Hook object to the library 37 | 38 | #include //From: https://github.com/mikalhart/TinyGPSPlus 39 | TinyGPSPlus gps; //Declare gps object 40 | 41 | //The following tells the TinyGPS library to scan for the PMTK001 sentence 42 | //This sentence is the response to a configure command from the user 43 | //Field 1 is the packet number, 2 indicates if configuration was successful 44 | TinyGPSCustom configureCmd(gps, "PMTK001", 1); //Packet number 45 | TinyGPSCustom configureFlag(gps, "PMTK001", 2); //Success/fail flag 46 | 47 | // The following tells the TinyGPS library to scan for the PMTK705 sentence. 48 | // This sentence is a response to a query of the firmware version 49 | TinyGPSCustom versionRelease(gps, "PMTK705", 1); // Release string 50 | TinyGPSCustom versionBuild(gps, "PMTK705", 2); // Build ID 51 | TinyGPSCustom versionModel(gps, "PMTK705", 3); // Product model 52 | // There can be a 4th version parameter but we are not terribly interested 53 | 54 | #define FW_OLD 1 55 | #define FW_NEW 2 56 | #define FW_UNKNOWN 0 57 | 58 | String configString; 59 | 60 | boolean debug = false; //Keeps track of the enable/disable of debug printing within the GPS lib 61 | 62 | void setup() 63 | { 64 | Serial.begin(115200); 65 | Serial.println("GPS Configuration Example"); 66 | 67 | if (myI2CGPS.begin() == false) 68 | { 69 | Serial.println("Module failed to respond. Please check wiring."); 70 | while (1); //Freeze! 71 | } 72 | Serial.println("GPS module found!"); 73 | 74 | //myI2CGPS.enableDebugging(); //Turn on printing of GPS strings 75 | myI2CGPS.disableDebugging(); //Turn off printing of GPS strings 76 | debug = false; 77 | 78 | printMenu(); 79 | } 80 | 81 | void loop() 82 | { 83 | if (Serial.available()) 84 | { 85 | byte incoming = Serial.read(); 86 | if (incoming == '1') 87 | { 88 | Serial.println(F("Make sure the baud rate is 57600bps or higher to reach 10Hz")); 89 | //Packet 220: Set time between fixes (update rate) 90 | //Milliseconds between output. 100 to 10,000 is allowed. 91 | //Example 1 Hz: ",1000" 92 | //Example 2 Hz: ",500" 93 | //Example 10 Hz: ",100" 94 | //NOTE: You must increase the baud rate to 57600bps or higher to reach 10Hz 95 | configString = myI2CGPS.createMTKpacket(220, ",100"); 96 | myI2CGPS.sendMTKpacket(configString); 97 | } 98 | else if (incoming == '2') 99 | { 100 | //Packet 220: Set time between fixes (update rate) 101 | //Milliseconds between output. 100 to 10,000 is allowed. 102 | configString = myI2CGPS.createMTKpacket(220, ",1000"); //Set to 1Hz 103 | myI2CGPS.sendMTKpacket(configString); 104 | } 105 | else if (incoming == '3') 106 | { 107 | //Packet 285: Set Pulse per second to occur after 3D fix, and blink for 25ms 108 | configString = myI2CGPS.createMTKpacket(285, ",2,25"); 109 | myI2CGPS.sendMTKpacket(configString); 110 | } 111 | else if (incoming == '4') 112 | { 113 | //Packet 314: The SET_NMEA_OUTPUT command is very long 114 | //20 types of sentences are allowed: GLL / RMC / VTG / GGA / GSA / GSV / GRS / GST 115 | //The number in the position sets the "output once every X position fixes" 116 | //Example: ",1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" = GLL only, output every fix 117 | //Example: ",0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" = RMC only, output every fix 118 | //Example: ",0,0,1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" = VTG every fix, GGA every 4th fix 119 | //Example: ",-1" = Reset to defaults 120 | configString = myI2CGPS.createMTKpacket(314, ",0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"); 121 | myI2CGPS.sendMTKpacket(configString); 122 | } 123 | else if (incoming == '5') 124 | { 125 | //Packet 886: Set navigation mode Normal=0 / Fitness=1 / Aviation=2 / Balloon=3 (80km space limit!) 126 | //Normal = general purpose 127 | //Fitness = Running and walking, less than 5m/s movement 128 | //Aviation = high dynamic large acceleration movement 129 | //Balloon = For high altitude ballooning! Allows max height to be up to 80km instead of 10km 130 | configString = myI2CGPS.createMTKpacket(886, ",3"); 131 | myI2CGPS.sendMTKpacket(configString); 132 | } 133 | else if (incoming == '6') 134 | { 135 | uint8_t FWversion = getFWversion(); 136 | 137 | if(FWversion == FW_OLD) 138 | { 139 | //Packet 251: Set serial baud rate to 57600 140 | configString = myI2CGPS.createMTKpacket(251, ",57600"); 141 | myI2CGPS.sendMTKpacket(configString); 142 | } 143 | else if(FWversion == FW_NEW) 144 | { 145 | configString = myI2CGPS.createPGCMDpacket(232, ",5"); 146 | myI2CGPS.sendPGCMDpacket(configString); 147 | 148 | configString = myI2CGPS.createMTKpacket(104, ""); 149 | myI2CGPS.sendMTKpacket(configString); 150 | } 151 | else 152 | { 153 | Serial.println(F("Firmware version unknown. Operation terminated.")); 154 | return; 155 | } 156 | 157 | 158 | Serial.println(F("Serial configuration command sent. No ACK is returned for this command.")); 159 | } 160 | else if (incoming == '7') 161 | { 162 | //Packet 301: Set DGPS mode 163 | //0 = No DGPS source 164 | //1 = RTCM 165 | //2 = SBAS(Includes WAAS/EGNOS/GAGAN/MSAS) 166 | //Note: You cannot enable SBAS/DGPS when update rate is faster than 5Hz 167 | configString = myI2CGPS.createMTKpacket(301, ",2"); 168 | myI2CGPS.sendMTKpacket(configString); 169 | } 170 | else if (incoming == '8') 171 | { 172 | if (debug == false) 173 | { 174 | myI2CGPS.enableDebugging(); 175 | debug = true; 176 | } 177 | else 178 | { 179 | myI2CGPS.disableDebugging(); 180 | debug = false; 181 | } 182 | } 183 | else if (incoming == '9') 184 | { 185 | //Packet 104: Reset to factory defaults 186 | //Erases all system and user configurations. Does cold start. 187 | //Note: Unit does not respond with an ACK packet 188 | //Note: If you're using an external anteanna you must power cycle the module 189 | //so that it detects the external antenna 190 | configString = myI2CGPS.createMTKpacket(104, ""); 191 | myI2CGPS.sendMTKpacket(configString); 192 | 193 | Serial.println(F("Reset command sent. No ACK is returned for this command.")); 194 | } 195 | else if(incoming == 'a') 196 | { 197 | // Check firmware version 198 | configString = myI2CGPS.createMTKpacket(605, ""); 199 | myI2CGPS.sendMTKpacket(configString); 200 | 201 | Serial.print("Querying GPS version: "); 202 | while(versionRelease.isUpdated() == false) 203 | { 204 | while (myI2CGPS.available()) //available() returns the number of new bytes available from the GPS module 205 | { 206 | gps.encode(myI2CGPS.read()); //Feed the GPS parser with a new .read() byte 207 | } 208 | Serial.print(F(".")); 209 | } 210 | Serial.println("done!"); 211 | 212 | Serial.print("Firmware version: "); 213 | Serial.println(versionRelease.value()); 214 | Serial.print("Build ID: "); 215 | Serial.println(versionBuild.value()); 216 | Serial.print("Model: "); 217 | Serial.println(versionModel.value()); 218 | Serial.println(); 219 | 220 | } 221 | else if(incoming == 's') 222 | { 223 | char baud_code = 0; 224 | uint8_t FWversion = FW_UNKNOWN; 225 | 226 | if(Serial.available() < 1) 227 | { 228 | Serial.println(F("Waiting for baud rate code. Enter a character '0' through '6'")); 229 | } 230 | while(Serial.available() < 1) 231 | { 232 | Serial.print(F(".")); 233 | delay(100); 234 | } 235 | 236 | baud_code = Serial.read(); 237 | 238 | if((baud_code < '0') || (baud_code > '6')) 239 | { 240 | Serial.println(F("Invalid baud rate code. Operation terminated")); 241 | return; 242 | } 243 | 244 | FWversion = getFWversion(); 245 | 246 | if(FWversion == FW_OLD) 247 | { 248 | switch(baud_code) 249 | { 250 | case '0' : 251 | configString = myI2CGPS.createMTKpacket(251, ",4800"); 252 | myI2CGPS.sendMTKpacket(configString); 253 | break; 254 | 255 | case '1' : 256 | configString = myI2CGPS.createMTKpacket(251, ",9600"); 257 | myI2CGPS.sendMTKpacket(configString); 258 | break; 259 | 260 | case '2' : 261 | configString = myI2CGPS.createMTKpacket(251, ",14400"); 262 | myI2CGPS.sendMTKpacket(configString); 263 | break; 264 | 265 | case '3' : 266 | configString = myI2CGPS.createMTKpacket(251, ",19200"); 267 | myI2CGPS.sendMTKpacket(configString); 268 | break; 269 | 270 | case '4' : 271 | configString = myI2CGPS.createMTKpacket(251, ",38400"); 272 | myI2CGPS.sendMTKpacket(configString); 273 | break; 274 | 275 | case '5' : 276 | configString = myI2CGPS.createMTKpacket(251, ",57600"); 277 | myI2CGPS.sendMTKpacket(configString); 278 | break; 279 | 280 | case '6' : 281 | configString = myI2CGPS.createMTKpacket(251, ",115200"); 282 | myI2CGPS.sendMTKpacket(configString); 283 | break; 284 | } 285 | } 286 | else if(FWversion == FW_NEW) 287 | { 288 | configString = myI2CGPS.createPGCMDpacket(232, (","+(String)baud_code)); 289 | myI2CGPS.sendPGCMDpacket(configString); 290 | 291 | configString = myI2CGPS.createMTKpacket(104, ""); 292 | myI2CGPS.sendMTKpacket(configString); 293 | } 294 | else 295 | { 296 | Serial.println(F("Baud rate NOT updated")); 297 | return; 298 | } 299 | Serial.println(F("Baud rate updated")); 300 | } 301 | else 302 | { 303 | printMenu(); 304 | } 305 | } 306 | 307 | while (myI2CGPS.available()) //available() returns the number of new bytes available from the GPS module 308 | { 309 | gps.encode(myI2CGPS.read()); //Feed the GPS parser with a new .read() byte 310 | } 311 | 312 | if (gps.time.isUpdated()) //Check to see if new GPS info is available 313 | { 314 | //displayInfo(); 315 | } 316 | 317 | //Check to see if we got a response from any command we recently sent 318 | if (configureCmd.isUpdated()) 319 | { 320 | Serial.print("Packet "); 321 | Serial.print(configureCmd.value()); 322 | Serial.print(": "); 323 | 324 | switch (configureFlag.value()[0]) 325 | { 326 | case '0': 327 | Serial.print(F("Invalid command")); 328 | break; 329 | case '1': 330 | Serial.print(F("Unsupported command")); 331 | break; 332 | case '2': 333 | Serial.print(F("Action failed")); 334 | break; 335 | case '3': 336 | Serial.print(F("Command successful")); 337 | break; 338 | } 339 | Serial.println(); 340 | } 341 | 342 | delay(10); 343 | } 344 | 345 | void printMenu(void) 346 | { 347 | Serial.println(); 348 | Serial.println(F("1) Set update rate to 10Hz")); 349 | Serial.println(F("2) Set update rate to 1Hz")); 350 | Serial.println(F("3) Enable PPS LED")); 351 | Serial.println(F("4) Turn off all sentences but RMC&GGA")); 352 | Serial.println(F("5) Enable high altitude balloon mode")); 353 | Serial.println(F("6) Set serial baud rate to 57600bps")); 354 | Serial.println(F("7) Enable DGPS/SBAS")); 355 | Serial.println(F("8) Enable/Disable Debugging")); 356 | Serial.println(F("9) Reset module")); 357 | Serial.println(F("a) Query version information")); 358 | Serial.println(F("s) Set baud rate:")); 359 | Serial.println(F("-- 0 : 4800")); 360 | Serial.println(F("-- 1 : 9600")); 361 | Serial.println(F("-- 2 : 14400")); 362 | Serial.println(F("-- 3 : 19200")); 363 | Serial.println(F("-- 4 : 38400")); 364 | Serial.println(F("-- 5 : 57600")); 365 | Serial.println(F("-- 6 : 115200")); 366 | 367 | Serial.println(); 368 | } 369 | 370 | void displayInfo() 371 | { 372 | //We have new GPS data to deal with! 373 | 374 | if (gps.time.hour() < 10) Serial.print(F("0")); 375 | Serial.print(gps.time.hour()); 376 | Serial.print(F(":")); 377 | if (gps.time.minute() < 10) Serial.print(F("0")); 378 | Serial.print(gps.time.minute()); 379 | Serial.print(F(":")); 380 | if (gps.time.second() < 10) Serial.print(F("0")); 381 | Serial.print(gps.time.second()); 382 | 383 | Serial.print(" Loc:"); 384 | Serial.print(gps.location.lat(), 6); 385 | Serial.print(F(",")); 386 | Serial.print(gps.location.lng(), 6); 387 | 388 | Serial.print(F(" SIV:")); 389 | Serial.print(gps.satellites.value()); 390 | 391 | Serial.print(F(" HDOP:")); 392 | Serial.print(gps.hdop.value()/100.0, 2); //TinyGPS reports DOPs in 100ths 393 | 394 | Serial.println(); 395 | } 396 | 397 | // This function uses the custom TinyGPS parser (versionRelease, versionBuild, and versionModel) 398 | // to try and dtermine if the GPS is running the new or old firmware. If neither can be determine then 399 | // it will return a third value to signify UNKNOWN 400 | // The old firmware - on Titan X1 models - uses exclusively PMTK commands 401 | // The new firmware added some commands and (unfortunately) removed some of the PMTK commands so it needs to be handled differently 402 | uint8_t getFWversion( void ) 403 | { 404 | // Check the firmware to determine what commands to use: 405 | configString = myI2CGPS.createMTKpacket(605, ""); 406 | myI2CGPS.sendMTKpacket(configString); 407 | while(versionRelease.isUpdated() == false) 408 | { 409 | while (myI2CGPS.available()) //available() returns the number of new bytes available from the GPS module 410 | { 411 | gps.encode(myI2CGPS.read()); //Feed the GPS parser with a new .read() byte 412 | } 413 | } 414 | // Now the most recent firmware version data exists 415 | 416 | if(versionRelease.value()[0] == 'A') 417 | { 418 | if(versionRelease.value()[4] >= '5') 419 | { 420 | return FW_NEW; 421 | } 422 | else 423 | { 424 | return FW_OLD; 425 | } 426 | } 427 | else if(versionRelease.value()[0] == 'M') 428 | { 429 | if(versionRelease.value()[6] >= '5') 430 | { 431 | return FW_NEW; 432 | } 433 | else 434 | { 435 | return FW_OLD; 436 | } 437 | } 438 | else 439 | { 440 | Serial.print(F("GPS firmware version (")); 441 | Serial.print(versionRelease.value()); 442 | Serial.println(F(") unknown. Operation terminated.")); 443 | return FW_UNKNOWN; 444 | } 445 | } 446 | 447 | -------------------------------------------------------------------------------- /externs.h: -------------------------------------------------------------------------------- 1 | #ifndef EXTERNS_H 2 | #define EXTERNS_H 3 | extern I2C i2c; 4 | extern Serial pc; 5 | #endif 6 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | I2CGPS KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | begin KEYWORD2 16 | check KEYWORD2 17 | available KEYWORD2 18 | read KEYWORD2 19 | sendMTKpacket KEYWORD2 20 | createMTKpacket KEYWORD2 21 | calcCRCforMTK KEYWORD2 22 | createPGCMDpacket KEYWORD2 23 | sendPGCMDpacket KEYWORD2 24 | 25 | enableDebugging KEYWORD2 26 | disableDebugging KEYWORD2 27 | 28 | ####################################### 29 | # Constants (LITERAL1) 30 | ####################################### 31 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun I2C GPS Reading and Control 2 | version=1.0.6 3 | author=SparkFun Electronics 4 | maintainer=SparkFun Electronics 5 | sentence=Library for the SparkFun Qwiic I2C GPS Module 6 | paragraph=An Arduino Library for the MediaTek MT3333 and MT3339 chipsets that enables the user to read GPS coordinates over I2C. Also supports the PMTK configuration protocol. This library only works with SparkFun modules that have been loaded with special firmware that enables the I2C interface. 7 | category=Sensors 8 | url=https://github.com/sparkfun/SparkFun_I2C_GPS_Arduino_Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mbed.h" 2 | #include "src/SparkFun_I2C_GPS_Reading_and_Control/SparkFun_I2C_GPS_Arduino_Library.h" 3 | #include "externs.h" 4 | 5 | I2C i2c(I2C1_SDA, I2C1_SCL); 6 | Serial pc(USBTX, USBRX, 115200); 7 | I2CGPS myI2CGPS; 8 | string configString; 9 | 10 | 11 | // main() runs in its own thread in the OS 12 | int main() { 13 | 14 | while (myI2CGPS.begin(i2c, 400000) == false) { 15 | pc.printf("Module failed to respond. Please check wiring.\n"); 16 | ThisThread::sleep_for(500); 17 | } 18 | pc.printf("GPS module found!\n"); 19 | 20 | /* if GPS module is found let us configure it */ 21 | // setup PPS LED 22 | configString = myI2CGPS.createMTKpacket(285, ",4,25"); 23 | myI2CGPS.sendMTKpacket(configString); 24 | 25 | 26 | while (true) { 27 | while (myI2CGPS.available()) // available() returns the number of new bytes 28 | // available from the GPS module 29 | { 30 | uint8_t incoming = myI2CGPS.read(); //Read the latest byte from Qwiic GPS 31 | if(incoming == '$') pc.printf("\n"); //Break the sentences onto new lines 32 | pc.printf("%c", incoming); //Print this character 33 | } 34 | } 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/SparkFun_I2C_GPS_Arduino_Library.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This is a library written for the MediaTek MT3333 based GPS module with I2C firmware 3 | specially loaded. SparkFun sells these at its website: www.sparkfun.com 4 | 5 | Written by Nathan Seidle @ SparkFun Electronics, April 25th, 2017 6 | 7 | This GPS module is special because it can use an I2C interface to communicate. 8 | 9 | This library handles the pulling in of data over I2C. We recommend a parsing engine 10 | such as TinyGPS. 11 | 12 | https://github.com/sparkfun/SparkFun_I2C_GPS_Arduino_Library 13 | 14 | Do you like this library? Help support SparkFun. Buy a board! 15 | 16 | Development environment specifics: 17 | Arduino IDE 1.8.1 18 | 19 | This program is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | GNU General Public License for more details. 23 | 24 | You should have received a copy of the GNU General Public License 25 | along with this program. If not, see . 26 | */ 27 | 28 | #include "SparkFun_I2C_GPS_Arduino_Library.h" 29 | 30 | #if defined(__MBED__) 31 | #include 32 | #include 33 | char dummy = 0; 34 | #endif 35 | 36 | //Sets up the sensor for constant read 37 | //Returns false if sensor does not respond 38 | #if defined (ARDUINO) || defined(PARTICLE) 39 | boolean I2CGPS::begin(TwoWire &wirePort, uint32_t i2cSpeed) 40 | { 41 | //Bring in the user's choices 42 | _i2cPort = &wirePort; //Grab which port the user wants us to use 43 | 44 | _i2cPort->begin(); 45 | _i2cPort->setClock(i2cSpeed); 46 | 47 | _head = 0; //Reset the location holder 48 | _tail = 0; 49 | 50 | //Ping the module to see if it responds 51 | _i2cPort->beginTransmission(MT333x_ADDR); 52 | _i2cPort->write((byte) 0x00); //Write dummy value 53 | _i2cPort->endTransmission(); 54 | 55 | if (_i2cPort->requestFrom(MT333x_ADDR, 1)) 56 | return (true); //Success! 57 | else 58 | return (false); //Module failed to respond 59 | } 60 | 61 | #elif defined(__MBED__) 62 | bool I2CGPS::begin(I2C &wirePort, uint32_t i2cSpeed) 63 | { 64 | //Bring in the user's choices 65 | _i2cPort = &wirePort; //Grab which port the user wants us to use 66 | 67 | _i2cPort->frequency(i2cSpeed); 68 | 69 | _head = 0; //Reset the location holder 70 | _tail = 0; 71 | 72 | _i2cPort->write(MT333x_ADDR << 1, (char *) &dummy, sizeof(dummy)); 73 | 74 | if (0 == _i2cPort->read(MT333x_ADDR << 1|1, (char *) &dummy, sizeof(dummy))) // might fail if current is unstable on GPIO pins 75 | return (true); 76 | else 77 | return (false); 78 | } 79 | #endif 80 | 81 | //Polls the GPS module to see if new data is available 82 | //Reads a 255 byte packet from GPS module 83 | //If new data is there, appends it to the gpsData array 84 | //Function requires 26ms @ 100kHz I2C, 9ms @ 400kHz I2C so call sparingly 85 | void I2CGPS::check() 86 | { 87 | //TODO: Re-write this function to be less tied to Arduino's 32 byte limit 88 | //Maybe pass a maxRead during .begin() 89 | 90 | for (uint8_t x = 0; x < MAX_PACKET_SIZE; x++) 91 | { 92 | #if defined (ARDUINO) || defined(PARTICLE) 93 | if (x % 32 == 0) //Arduino can only Wire.read() in 32 byte chunks. Yay. 94 | _i2cPort->requestFrom(MT333x_ADDR, 32); //Request 32 more bytes 95 | 96 | uint8_t incoming = _i2cPort->read(); 97 | #elif defined (__MBED__) 98 | uint8_t incoming; 99 | _i2cPort->read(MT333x_ADDR << 1|1, (char *)&incoming, 1); 100 | #endif 101 | 102 | if (incoming != 0x0A) 103 | { 104 | //Record this byte 105 | gpsData[_head++] = incoming; 106 | _head %= MAX_PACKET_SIZE; //Wrap variable 107 | 108 | if (_printDebug == true && _head == _tail) 109 | #if defined (ARDUINO) || defined(PARTICLE) 110 | _debugSerial->println(F("Buffer overrun")); 111 | #elif defined (__MBED__) 112 | _debugSerial->printf("Buffer overrun\n"); 113 | #endif 114 | } 115 | } 116 | } 117 | 118 | //Returns # of available bytes that can be read 119 | uint8_t I2CGPS::available() 120 | { 121 | //If tail=head then no new data is available in the local buffer 122 | //So now check to see if the module has anything new in its buffer 123 | if (_tail == _head) 124 | { 125 | check(); //Check to module to see if new I2C bytes are available 126 | } 127 | 128 | //Return new data count 129 | if (_head > _tail) 130 | return (_head - _tail); 131 | if (_tail > _head) 132 | return (MAX_PACKET_SIZE - _tail + _head); 133 | return (0); //No data available 134 | } 135 | 136 | //Returns the next available byte from the gpsData array 137 | //Returns 0 if no byte available 138 | uint8_t I2CGPS::read(void) 139 | { 140 | if (_tail != _head) 141 | { 142 | uint8_t datum = gpsData[_tail++]; 143 | if (_tail == MAX_PACKET_SIZE) 144 | _tail = 0; //Wrap variable 145 | return (datum); 146 | } 147 | else 148 | return (0); //No new data 149 | } 150 | 151 | //Enables serial printing of local error messages 152 | void I2CGPS::enableDebugging(Stream &debugPort) 153 | { 154 | _debugSerial = &debugPort; //Grab which port the user wants us to use for debugging 155 | 156 | _printDebug = true; //Should we print the commands we send? Good for debugging 157 | } 158 | 159 | //Turn off printing of GPS character streams 160 | void I2CGPS::disableDebugging() 161 | { 162 | _printDebug = false; //Turn off extra print statements 163 | } 164 | 165 | //Functions for sending commands to the GPS module 166 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 167 | 168 | //Send a given command or configuration string to the module 169 | //The input buffer on the MTK is 255 bytes. Caller must keep strings shorter than 255 bytes 170 | //Any time you end transmission you must give the module 10ms to process bytes 171 | #if defined (ARDUINO) || defined(PARTICLE) 172 | boolean I2CGPS::sendMTKpacket(String command) 173 | { 174 | if (command.length() > 255) 175 | { 176 | if (_printDebug == true) 177 | _debugSerial->println(F("Command message too long!")); 178 | 179 | return (false); 180 | } 181 | 182 | //Arduino can only Wire.write() in 32 byte chunks. Yay. 183 | for (uint8_t chunk = 0; chunk < 7; chunk++) //8 chunks * 32 = 256 bytes total so we need to shave one 184 | { 185 | _i2cPort->beginTransmission(MT333x_ADDR); 186 | for (uint8_t x = 0; x < 32; x++) //Send out 32 bytes 187 | { 188 | if ((chunk * 32 + x) == command.length()) 189 | break; //We're done! 190 | _i2cPort->write(command[(chunk * 32) + x]); 191 | } 192 | _i2cPort->endTransmission(); 193 | 194 | delay(10); //Slave requires 10 ms to process incoming bytes 195 | } 196 | 197 | //Send final 31 bytes 198 | if (command.length() > (7 * 32)) //Do we have more than 224 bytes? Then send last 31 199 | { 200 | _i2cPort->beginTransmission(MT333x_ADDR); 201 | for (uint8_t x = 0; x < 31; x++) //Write any remaining bytes up to 255 202 | { 203 | if ((7 * 32 + x) == command.length()) 204 | break; //We're done! 205 | _i2cPort->write(command[(7 * 32) + x]); 206 | } 207 | _i2cPort->endTransmission(); 208 | } 209 | 210 | return (true); 211 | } 212 | 213 | #elif defined (__MBED__) 214 | bool I2CGPS::sendMTKpacket(string command) 215 | { 216 | if (command.length() > 255) 217 | { 218 | if (_printDebug == true) 219 | _debugSerial->printf("Command message too long!\n"); 220 | 221 | return (false); 222 | } 223 | 224 | _i2cPort->write(MT333x_ADDR << 1, command.c_str(), command.length()); 225 | ThisThread::sleep_for(10); 226 | 227 | return (true); 228 | } 229 | #endif 230 | 231 | //Given a packetType and any settings, return string that is a full 232 | //config sentence complete with CRC and \r \n ending bytes 233 | //PMTK uses a different packet numbers to do configure the module. 234 | //These vary from 0 to 999. See 'MTK NMEA Packet' datasheet for more info. 235 | #if defined (ARDUINO) || defined(PARTICLE) 236 | String I2CGPS::createMTKpacket(uint16_t packetType, String dataField) 237 | { 238 | //Build config sentence using packetType 239 | String configSentence = ""; 240 | #elif defined (__MBED__) 241 | string I2CGPS::createMTKpacket(uint16_t packetType, string dataField) 242 | { 243 | //Build config sentence using packetType 244 | string configSentence = ""; 245 | #endif 246 | configSentence += "$PMTK"; //Default header for all GPS config messages 247 | 248 | //Attach the packetType number 249 | //Append any leading zeros 250 | if (packetType < 100) 251 | configSentence += "0"; 252 | if (packetType < 10) 253 | configSentence += "0"; 254 | #if defined (ARDUINO) || defined(PARTICLE) 255 | configSentence += String(packetType); 256 | #elif defined (__MBED__) 257 | configSentence += to_string(packetType); 258 | #endif 259 | 260 | //Attach any settings 261 | if (dataField.length() > 0) 262 | { 263 | configSentence += dataField; //Attach the string of flags 264 | } 265 | 266 | configSentence += "*"; //Attach end tag 267 | 268 | configSentence += calcCRCforMTK(configSentence); //Attach CRC 269 | 270 | //Attach ending bytes 271 | configSentence += '\r'; //Carriage return 272 | configSentence += '\n'; //Line feed 273 | 274 | return (configSentence); 275 | } 276 | 277 | //Calculate CRC for MTK messages 278 | //Given a string of characters, XOR them all together and return CRC in string form 279 | #if defined (ARDUINO) || defined(PARTICLE) 280 | String I2CGPS::calcCRCforMTK(String sentence) 281 | { 282 | #elif defined (__MBED__) 283 | string I2CGPS::calcCRCforMTK(string sentence) 284 | { 285 | #endif 286 | uint8_t crc = 0; 287 | 288 | //We need to ignore the first character $ 289 | //And the last character * 290 | for (uint8_t x = 1; x < sentence.length() - 1; x++) 291 | crc ^= sentence[x]; //XOR this byte with all the others 292 | 293 | #if defined (ARDUINO) || defined(PARTICLE) 294 | String output = ""; 295 | #elif defined (__MBED__) 296 | string output = ""; 297 | #endif 298 | if (crc < 10) 299 | output += "0"; //Append leading zero if needed 300 | 301 | #if defined (ARDUINO) || defined(PARTICLE) 302 | output += String(crc, HEX); 303 | #elif defined (__MBED__) 304 | static char outhex[4]; 305 | sprintf(outhex, "%02X", crc); 306 | 307 | output += outhex; 308 | #endif 309 | 310 | return (output); 311 | } 312 | 313 | #if defined (ARDUINO) || defined(PARTICLE) 314 | boolean I2CGPS::sendPGCMDpacket(String command) 315 | { 316 | #elif defined (__MBED__) 317 | bool I2CGPS::sendPGCMDpacket(string command) 318 | { 319 | #endif 320 | return (sendMTKpacket(command)); // Send process is the same, re-named to ease user's minds 321 | } 322 | 323 | #if defined (ARDUINO) || defined(PARTICLE) 324 | String I2CGPS::createPGCMDpacket(uint16_t packetType, String dataField) 325 | { 326 | //Build config sentence using packetType 327 | String configSentence = ""; 328 | #elif defined (__MBED__) 329 | string I2CGPS::createPGCMDpacket(uint16_t packetType, string dataField) 330 | { 331 | //Build config sentence using packetType 332 | string configSentence = ""; 333 | #endif 334 | configSentence += "$PGCMD,"; //Default header for all PGCMD messages 335 | 336 | //Attach the packetType number 337 | //Append any leading zeros 338 | if (packetType < 100) 339 | configSentence += "0"; 340 | if (packetType < 10) 341 | configSentence += "0"; 342 | #if defined (ARDUINO) || defined(PARTICLE) 343 | configSentence += String(packetType); 344 | #elif defined (__MBED__) 345 | configSentence += to_string(packetType); 346 | #endif 347 | 348 | //Attach any settings 349 | if (dataField.length() > 0) 350 | { 351 | configSentence += dataField; //Attach the string of flags 352 | } 353 | 354 | configSentence += "*"; //Attach end tag 355 | 356 | configSentence += calcCRCforMTK(configSentence); //Attach CRC - uses the same crc as PTMK 357 | 358 | //Attach ending bytes 359 | configSentence += '\r'; //Carriage return 360 | configSentence += '\n'; //Line feed 361 | 362 | return (configSentence); 363 | } 364 | -------------------------------------------------------------------------------- /src/SparkFun_I2C_GPS_Arduino_Library.h: -------------------------------------------------------------------------------- 1 | /* 2 | This is a library written for the MediaTek MT3333 based GPS module with I2C firmware 3 | specially loaded. SparkFun sells these at its website: www.sparkfun.com 4 | 5 | Written by Nathan Seidle @ SparkFun Electronics, April 25th, 2017 6 | 7 | This GPS module is special because it can use an I2C interface to communicate. 8 | 9 | This library handles the pulling in of data over I2C. We recommend a parsing engine 10 | such as TinyGPS. 11 | 12 | https://github.com/sparkfun/SparkFun_I2C_GPS_Arduino_Library 13 | 14 | Do you like this library? Help support SparkFun. Buy a board! 15 | 16 | Development environment specifics: 17 | Arduino IDE 1.8.1 18 | 19 | This program is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | GNU General Public License for more details. 23 | 24 | You should have received a copy of the GNU General Public License 25 | along with this program. If not, see . 26 | */ 27 | 28 | #pragma once 29 | 30 | #if defined(ARDUINO) && ARDUINO >= 100 31 | #include "Arduino.h" 32 | #include 33 | #elif defined(ARDUINO) && ARDUINO < 100 34 | #include "WProgram.h" 35 | #include 36 | #elif defined(__MBED__) 37 | #include "mbed.h" 38 | #include "externs.h" 39 | #include 40 | #include 41 | #include "TinyGPSPlus/TinyGPS++.h" 42 | #elif defined(PARTICLE) 43 | #include"Particle.h" 44 | #endif 45 | 46 | 47 | 48 | #define MT333x_ADDR 0x10 //7-bit unshifted default I2C Address 49 | 50 | #define MAX_PACKET_SIZE 255 51 | //If packet size is ever more than 255 the head and tail variables will need to be 52 | //changed to something other than uint8_t 53 | 54 | #define I2C_SPEED_STANDARD 100000 55 | #define I2C_SPEED_FAST 400000 56 | 57 | class I2CGPS { 58 | public: 59 | 60 | //By default use Wire, standard I2C speed, and the default AK9750 address 61 | #if defined(ARDUINO) || defined(PARTICLE) 62 | boolean begin(TwoWire &wirePort = Wire, uint32_t i2cSpeed = I2C_SPEED_STANDARD); 63 | #elif defined (__MBED__) 64 | bool begin(I2C &wirePort = i2c, uint32_t i2cSpeed = I2C_SPEED_STANDARD); 65 | #endif 66 | 67 | void check(); //Checks module for new data 68 | uint8_t available(); //Returns available number of bytes. Will call check() if zero is available. 69 | uint8_t read(); //Returns the next available byte 70 | 71 | #if defined(ARDUINO) || defined(PARTICLE) 72 | void enableDebugging(Stream &debugPort = Serial); //Output various extra messages to help with debug 73 | #elif defined (__MBED__) 74 | void enableDebugging(Stream &debugPort = pc); 75 | #endif 76 | 77 | void disableDebugging(); 78 | 79 | #if defined(ARDUINO) || defined(PARTICLE) 80 | boolean sendMTKpacket(String command); 81 | String createMTKpacket(uint16_t packetType, String dataField); 82 | String calcCRCforMTK(String sentence); //XORs all bytes between $ and * 83 | 84 | boolean sendPGCMDpacket(String command); 85 | String createPGCMDpacket(uint16_t packetType, String dataField); 86 | // Uses MTK CRC 87 | 88 | #elif defined (__MBED__) 89 | bool sendMTKpacket(string command); 90 | string createMTKpacket(uint16_t packetType, string dataField); 91 | string calcCRCforMTK(string sentence); //XORs all bytes between $ and * 92 | 93 | bool sendPGCMDpacket(string command); 94 | string createPGCMDpacket(uint16_t packetType, string dataField); 95 | #endif 96 | 97 | //Variables 98 | uint8_t gpsData[MAX_PACKET_SIZE]; //The place to store valid incoming gps data 99 | 100 | private: 101 | 102 | //Variables 103 | #if defined(ARDUINO) || defined(PARTICLE) 104 | TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware 105 | boolean _printDebug = false; //Flag to print the serial commands we are sending to the Serial port for debug 106 | #elif defined (__MBED__) 107 | I2C *_i2cPort; //The generic connection to user's chosen I2C hardware 108 | bool _printDebug = false; //Flag to print the serial commands we are sending to the Serial port for debug 109 | #endif 110 | uint8_t _i2caddr; 111 | 112 | 113 | 114 | Stream *_debugSerial; //The stream to send debug messages to if enabled 115 | 116 | uint8_t _head; //Location of next available spot in the gpsData array. Limited to 255. 117 | uint8_t _tail; //Location of last spot read from gpsData array. Limited to 255. 118 | }; 119 | --------------------------------------------------------------------------------