diff --git a/Adafruit_GPS.cpp b/Adafruit_GPS.cpp index b32a501..3c63e68 100755 --- a/Adafruit_GPS.cpp +++ b/Adafruit_GPS.cpp @@ -28,10 +28,6 @@ */ /**************************************************************************/ -#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) - // Only include software serial on AVR platforms and ESP8266 (i.e. not on Due). - #include -#endif #include #define MAXLINELENGTH 120 ///< how long are max NMEA lines to parse? @@ -385,6 +381,57 @@ float Adafruit_GPS::secondsSinceDate() { return (millis()-lastDate) / 1000.; } +/**************************************************************************/ +/*! + @brief How many bytes are available to read - part of 'Print'-class functionality + @return Bytes available, 0 if none +*/ +/**************************************************************************/ +size_t Adafruit_GPS::available(void) { + if (paused) return 0; + +#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) + if (gpsSwSerial) { + return gpsSwSerial->available(); + } +#endif + if (gpsHwSerial) { + return gpsHwSerial->available(); + } + if (gpsI2C) { + return 1; // I2C doesnt have 'availability' so always has a byte at least to read! + } + return 0; +} + +/**************************************************************************/ +/*! + @brief Write a byte to the underlying transport - part of 'Print'-class functionality + @param c A single byte to send + @return Bytes written - 1 on success, 0 on failure +*/ +/**************************************************************************/ +size_t Adafruit_GPS::write(uint8_t c) { +#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) + if (gpsSwSerial) { + return gpsSwSerial->write(c); + } +#endif + if (gpsHwSerial) { + return gpsHwSerial->write(c); + } + if (gpsI2C) { + gpsI2C->beginTransmission(_i2caddr); + if (gpsI2C->write(c) != 1) { + return 0; + } + if (gpsI2C->endTransmission(true) == 0) { + return 1; + } + } + return 0; +} + /**************************************************************************/ /*! @brief Read one character from the GPS device @@ -400,21 +447,48 @@ char Adafruit_GPS::read(void) { #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) if(gpsSwSerial) { - if(!gpsSwSerial->available()) return c; + if (!gpsSwSerial->available()) + return c; c = gpsSwSerial->read(); - } else + } #endif - { - if(!gpsHwSerial->available()) return c; + if (gpsHwSerial) { + if (!gpsHwSerial->available()) + return c; c = gpsHwSerial->read(); } - + if (gpsI2C) { + if (_i2cbuff_idx <= _i2cbuff_max) { + c = _i2cbuffer[_i2cbuff_idx]; + _i2cbuff_idx++; + } else { + // refill the buffer! + if (Wire.requestFrom(0x10, GPS_MAX_I2C_TRANSFER, true) == GPS_MAX_I2C_TRANSFER) { + // got data! + _i2cbuff_max = 0; + char curr_char = 0; + for (int i=0; i= MAXLINELENGTH) lineidx = MAXLINELENGTH-1; // ensure there is someplace to put the next received character @@ -470,6 +544,17 @@ Adafruit_GPS::Adafruit_GPS(HardwareSerial *ser) { gpsHwSerial = ser; // ...override gpsHwSerial with value passed. } +/**************************************************************************/ +/*! + @brief Constructor when using I2C + @param theWire Pointer to an I2C TwoWire object +*/ +/**************************************************************************/ +Adafruit_GPS::Adafruit_GPS(TwoWire *theWire) { + common_init(); // Set everything to common state, then... + gpsI2C = theWire; // ...override gpsI2C +} + /**************************************************************************/ /*! @brief Initialization code used by all constructor types @@ -480,6 +565,7 @@ void Adafruit_GPS::common_init(void) { gpsSwSerial = NULL; // Set both to NULL, then override correct #endif gpsHwSerial = NULL; // port pointer in corresponding constructor + gpsI2C = NULL; recvdflag = false; paused = false; lineidx = 0; @@ -498,19 +584,33 @@ void Adafruit_GPS::common_init(void) { /**************************************************************************/ /*! @brief Start the HW or SW serial port - @param baud Baud rate + @param baud_or_i2caddr Baud rate if using serial, I2C address if using I2C + @returns True on successful hardware init, False on failure */ /**************************************************************************/ -void Adafruit_GPS::begin(uint32_t baud) +bool Adafruit_GPS::begin(uint32_t baud_or_i2caddr) { #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) - if(gpsSwSerial) - gpsSwSerial->begin(baud); - else + if(gpsSwSerial) { + gpsSwSerial->begin(baud_or_i2caddr); + } #endif - gpsHwSerial->begin(baud); - + if (gpsHwSerial) { + gpsHwSerial->begin(baud_or_i2caddr); + } + if (gpsI2C) { + gpsI2C->begin(); + if (baud_or_i2caddr > 0x7F) { + _i2caddr = GPS_DEFAULT_I2C_ADDR; + } else { + _i2caddr = baud_or_i2caddr; + } + // A basic scanner, see if it ACK's + gpsI2C->beginTransmission(_i2caddr); + return (gpsI2C->endTransmission () == 0); + } delay(10); + return true; } /**************************************************************************/ @@ -520,12 +620,7 @@ void Adafruit_GPS::begin(uint32_t baud) */ /**************************************************************************/ void Adafruit_GPS::sendCommand(const char *str) { -#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) - if(gpsSwSerial) - gpsSwSerial->println(str); - else -#endif - gpsHwSerial->println(str); + println(str); } /**************************************************************************/ diff --git a/Adafruit_GPS.h b/Adafruit_GPS.h index a128f04..4b6ff01 100644 --- a/Adafruit_GPS.h +++ b/Adafruit_GPS.h @@ -27,11 +27,15 @@ #define _ADAFRUIT_GPS_H #define USE_SW_SERIAL ///< comment this out if you don't want to include software serial in the library +#define GPS_DEFAULT_I2C_ADDR 0x10 ///< The default address for I2C transport of GPS data +#define GPS_MAX_I2C_TRANSFER 32 ///< The max number of bytes we'll try to read at once #include "Arduino.h" #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) #include #endif +#include + /**************************************************************************/ /** @@ -98,14 +102,15 @@ /*! @brief The GPS class */ -class Adafruit_GPS { +class Adafruit_GPS : public Print{ public: - void begin(uint32_t baud); + bool begin(uint32_t baud_or_i2caddr); #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) Adafruit_GPS(SoftwareSerial *ser); // Constructor when using SoftwareSerial #endif Adafruit_GPS(HardwareSerial *ser); // Constructor when using HardwareSerial + Adafruit_GPS(TwoWire *theWire); // Constructor when using I2C char *lastNMEA(void); boolean newNMEAreceived(); @@ -118,6 +123,9 @@ class Adafruit_GPS { uint8_t parseHex(char c); char read(void); + size_t write(uint8_t); + size_t available(void); + boolean parse(char *); float secondsSinceFix(); float secondsSinceTime(); @@ -195,6 +203,11 @@ class Adafruit_GPS { SoftwareSerial *gpsSwSerial; #endif HardwareSerial *gpsHwSerial; + TwoWire *gpsI2C; + uint8_t _i2caddr; + char _i2cbuffer[GPS_MAX_I2C_TRANSFER]; + int8_t _i2cbuff_max = -1, _i2cbuff_idx = 0; + char last_char = 0; }; /**************************************************************************/ diff --git a/examples/GPS_I2C_EchoTest/GPS_I2C_EchoTest.ino b/examples/GPS_I2C_EchoTest/GPS_I2C_EchoTest.ino new file mode 100644 index 0000000..6887ac8 --- /dev/null +++ b/examples/GPS_I2C_EchoTest/GPS_I2C_EchoTest.ino @@ -0,0 +1,35 @@ +// Test code for Adafruit GPS That Support Using I2C +// +// This code shows how to test a passthru between USB and I2C +// +// Pick one up today at the Adafruit electronics shop +// and help support open source hardware & software! -ada + +#include + +// Connect to the GPS on the hardware I2C port +Adafruit_GPS GPS(&Wire); + + +void setup() { + // wait for hardware serial to appear + while (!Serial); + + // make this baud rate fast enough to we aren't waiting on it + Serial.begin(115200); + + Serial.println("Adafruit GPS library basic I2C test!"); + GPS.begin(0x10); // The I2C address to use is 0x10 +} + + +void loop() { + if (Serial.available()) { + char c = Serial.read(); + GPS.write(c); + } + if (GPS.available()) { + char c = GPS.read(); + Serial.write(c); + } +} \ No newline at end of file diff --git a/examples/GPS_I2C_OLEDdebug/GPS_I2C_OLEDdebug.ino b/examples/GPS_I2C_OLEDdebug/GPS_I2C_OLEDdebug.ino new file mode 100644 index 0000000..7ed245b --- /dev/null +++ b/examples/GPS_I2C_OLEDdebug/GPS_I2C_OLEDdebug.ino @@ -0,0 +1,35 @@ +// Test code for Adafruit GPS That Support Using I2C +// +// This code shows how to test a passthru between USB and I2C +// +// Pick one up today at the Adafruit electronics shop +// and help support open source hardware & software! -ada + +#include + +// Connect to the GPS on the hardware I2C port +Adafruit_GPS GPS(&Wire); + + +void setup() { + // wait for hardware serial to appear + while (!Serial); + + // make this baud rate fast enough to we aren't waiting on it + Serial.begin(115200); + + Serial.println("Adafruit GPS library basic I2C test!"); + GPS.begin(0x10); // The I2C address to use is 0x10 +} + + +void loop() { + if (Serial.available()) { + char c = Serial.read(); + GPS.write(c); + } + if (GPS.available()) { + char c = GPS.read(); + Serial.write(c); + } +} diff --git a/examples/GPS_I2C_Parsing/GPS_I2C_Parsing.ino b/examples/GPS_I2C_Parsing/GPS_I2C_Parsing.ino new file mode 100644 index 0000000..6e251d3 --- /dev/null +++ b/examples/GPS_I2C_Parsing/GPS_I2C_Parsing.ino @@ -0,0 +1,103 @@ +// Test code for Adafruit GPS That Support Using I2C +// +// This code shows how to parse data from the I2C GPS +// +// Pick one up today at the Adafruit electronics shop +// and help support open source hardware & software! -ada + +#include + +// Connect to the GPS on the hardware I2C port +Adafruit_GPS GPS(&Wire); + +// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console +// Set to 'true' if you want to debug and listen to the raw GPS sentences +#define GPSECHO false + +uint32_t timer = millis(); + + +void setup() +{ + //while (!Serial); // uncomment to have the sketch wait until Serial is ready + + // connect at 115200 so we can read the GPS fast enough and echo without dropping chars + // also spit it out + Serial.begin(115200); + Serial.println("Adafruit I2C GPS library basic test!"); + + // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800 + GPS.begin(0x10); // The I2C address to use is 0x10 + // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude + GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); + // uncomment this line to turn on only the "minimum recommended" data + //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY); + // For parsing data, we don't suggest using anything but either RMC only or RMC+GGA since + // the parser doesn't care about other sentences at this time + // Set the update rate + GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate + // For the parsing code to work nicely and have time to sort thru the data, and + // print it out we don't suggest using anything higher than 1 Hz + + // Request updates on antenna status, comment out to keep quiet + GPS.sendCommand(PGCMD_ANTENNA); + + delay(1000); + + // Ask for firmware version + GPS.println(PMTK_Q_RELEASE); +} + +void loop() // run over and over again +{ + // read data from the GPS in the 'main loop' + char c = GPS.read(); + // if you want to debug, this is a good time to do it! + if (GPSECHO) + if (c) Serial.print(c); + // if a sentence is received, we can check the checksum, parse it... + if (GPS.newNMEAreceived()) { + // a tricky thing here is if we print the NMEA sentence, or data + // we end up not listening and catching other sentences! + // so be very wary if using OUTPUT_ALLDATA and trying to print out data + Serial.println(GPS.lastNMEA()); // this also sets the newNMEAreceived() flag to false + if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false + return; // we can fail to parse a sentence in which case we should just wait for another + } + // if millis() or timer wraps around, we'll just reset it + if (timer > millis()) timer = millis(); + + // approximately every 2 seconds or so, print out the current stats + if (millis() - timer > 2000) { + timer = millis(); // reset the timer + Serial.print("\nTime: "); + if (GPS.hour < 10) { Serial.print('0'); } + Serial.print(GPS.hour, DEC); Serial.print(':'); + if (GPS.minute < 10) { Serial.print('0'); } + Serial.print(GPS.minute, DEC); Serial.print(':'); + if (GPS.seconds < 10) { Serial.print('0'); } + Serial.print(GPS.seconds, DEC); Serial.print('.'); + if (GPS.milliseconds < 10) { + Serial.print("00"); + } else if (GPS.milliseconds > 9 && GPS.milliseconds < 100) { + Serial.print("0"); + } + Serial.println(GPS.milliseconds); + Serial.print("Date: "); + Serial.print(GPS.day, DEC); Serial.print('/'); + Serial.print(GPS.month, DEC); Serial.print("/20"); + Serial.println(GPS.year, DEC); + Serial.print("Fix: "); Serial.print((int)GPS.fix); + Serial.print(" quality: "); Serial.println((int)GPS.fixquality); + if (GPS.fix) { + Serial.print("Location: "); + Serial.print(GPS.latitude, 4); Serial.print(GPS.lat); + Serial.print(", "); + Serial.print(GPS.longitude, 4); Serial.println(GPS.lon); + Serial.print("Speed (knots): "); Serial.println(GPS.speed); + Serial.print("Angle: "); Serial.println(GPS.angle); + Serial.print("Altitude: "); Serial.println(GPS.altitude); + Serial.print("Satellites: "); Serial.println((int)GPS.satellites); + } + } +} \ No newline at end of file