From d213ccc4cfa0e1dd8310c31724d06fa98d63de6f Mon Sep 17 00:00:00 2001 From: Ladyada Date: Fri, 30 Aug 2019 02:18:01 -0400 Subject: [PATCH 1/6] basic i2c interfacing, GPS now subclasses Print so we can treat it like a serial connection --- Adafruit_GPS.cpp | 143 ++++++++++++++++++++++++++++++++++++++--------- Adafruit_GPS.h | 16 +++++- 2 files changed, 130 insertions(+), 29 deletions(-) diff --git a/Adafruit_GPS.cpp b/Adafruit_GPS.cpp index 963ccda..f057b4d 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,47 @@ float Adafruit_GPS::secondsSinceDate() { return (millis()-lastDate) / 1000.; } + +size_t Adafruit_GPS::available(void) { + char c = 0; + + if (paused) return c; + +#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 false; +} + +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 @@ -398,21 +435,51 @@ 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 last_char = 0, curr_char = 0; + for (int i=0; i= MAXLINELENGTH) lineidx = MAXLINELENGTH-1; // ensure there is someplace to put the next received character @@ -464,6 +531,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 @@ -474,6 +552,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; @@ -492,19 +571,34 @@ 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; + } + gpsI2C->setClock(400000); + // A basic scanner, see if it ACK's + gpsI2C->beginTransmission(_i2caddr); + return (gpsI2C->endTransmission () == 0); + } delay(10); + return true; } /**************************************************************************/ @@ -514,12 +608,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 4ee45c6..3a33946 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 #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(); @@ -194,6 +202,10 @@ 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; }; /**************************************************************************/ From c9632ab73ccc196d24f44b62e4bc6e98b144b3f9 Mon Sep 17 00:00:00 2001 From: Ladyada Date: Fri, 30 Aug 2019 02:21:23 -0400 Subject: [PATCH 2/6] basic i2c demo --- .../GPS_I2C_EchoTest/GPS_I2C_EchoTest.ino | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 examples/GPS_I2C_EchoTest/GPS_I2C_EchoTest.ino 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 From 2213c0343964b57eae433fa8c8391670018fe04f Mon Sep 17 00:00:00 2001 From: ladyada Date: Wed, 9 Oct 2019 16:51:17 -0400 Subject: [PATCH 3/6] more workin' on i2c --- Adafruit_GPS.cpp | 11 ++---- .../GPS_I2C_OLEDdebug/GPS_I2C_OLEDdebug.ino | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 examples/GPS_I2C_OLEDdebug/GPS_I2C_OLEDdebug.ino diff --git a/Adafruit_GPS.cpp b/Adafruit_GPS.cpp index f057b4d..67ed335 100755 --- a/Adafruit_GPS.cpp +++ b/Adafruit_GPS.cpp @@ -383,9 +383,7 @@ float Adafruit_GPS::secondsSinceDate() { size_t Adafruit_GPS::available(void) { - char c = 0; - - if (paused) return c; + if (paused) return 0; #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) if (gpsSwSerial) { @@ -398,7 +396,7 @@ size_t Adafruit_GPS::available(void) { if (gpsI2C) { return 1; // I2C doesnt have 'availability' so always has a byte at least to read! } - return false; + return 0; } size_t Adafruit_GPS::write(uint8_t c) { @@ -476,10 +474,6 @@ char Adafruit_GPS::read(void) { //Serial.print(c); - // if (c == '$') { //please don't eat the dollar sign - rdl 9/15/14 - // currentline[lineidx] = 0; - // lineidx = 0; - // } currentline[lineidx++] = c; if (lineidx >= MAXLINELENGTH) lineidx = MAXLINELENGTH-1; // ensure there is someplace to put the next received character @@ -592,7 +586,6 @@ bool Adafruit_GPS::begin(uint32_t baud_or_i2caddr) } else { _i2caddr = baud_or_i2caddr; } - gpsI2C->setClock(400000); // A basic scanner, see if it ACK's gpsI2C->beginTransmission(_i2caddr); return (gpsI2C->endTransmission () == 0); 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); + } +} From ceabac597fd8cc52bb0a51d850799537c252dffa Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 13 Oct 2019 20:15:13 -0400 Subject: [PATCH 4/6] nice kleen output! --- Adafruit_GPS.cpp | 5 +++-- Adafruit_GPS.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Adafruit_GPS.cpp b/Adafruit_GPS.cpp index 67ed335..5e5b341 100755 --- a/Adafruit_GPS.cpp +++ b/Adafruit_GPS.cpp @@ -452,10 +452,11 @@ char Adafruit_GPS::read(void) { if (Wire.requestFrom(0x10, GPS_MAX_I2C_TRANSFER, true) == GPS_MAX_I2C_TRANSFER) { // got data! _i2cbuff_max = 0; - char last_char = 0, curr_char = 0; + char curr_char = 0; for (int i=0; i Date: Sun, 13 Oct 2019 20:22:14 -0400 Subject: [PATCH 5/6] parsingdemo --- examples/GPS_I2C_Parsing/GPS_I2C_Parsing.ino | 103 +++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 examples/GPS_I2C_Parsing/GPS_I2C_Parsing.ino 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 From 70bea470db31d9bf17f65412d6d5e48c3b243d74 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 13 Oct 2019 21:32:50 -0400 Subject: [PATCH 6/6] doxy new Print support --- Adafruit_GPS.cpp | 14 +++++++++++++- Adafruit_GPS.h | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Adafruit_GPS.cpp b/Adafruit_GPS.cpp index 5e5b341..e56d8ea 100755 --- a/Adafruit_GPS.cpp +++ b/Adafruit_GPS.cpp @@ -381,7 +381,12 @@ 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; @@ -399,6 +404,13 @@ size_t Adafruit_GPS::available(void) { 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) { diff --git a/Adafruit_GPS.h b/Adafruit_GPS.h index 4821896..e068884 100644 --- a/Adafruit_GPS.h +++ b/Adafruit_GPS.h @@ -28,7 +28,7 @@ #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 +#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)