From d213ccc4cfa0e1dd8310c31724d06fa98d63de6f Mon Sep 17 00:00:00 2001 From: Ladyada Date: Fri, 30 Aug 2019 02:18:01 -0400 Subject: [PATCH] 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; }; /**************************************************************************/