Bläddra i källkod

Merge pull request #332 from cod3doomy/dev

RAK4631: Add GPS support
ripplebiz 1 år sedan
förälder
incheckning
4a7d273db4

+ 11 - 0
src/helpers/nrf52/RAK4631Board.h

@@ -12,6 +12,17 @@
 #define  P_LORA_MISO    45
 #define  P_LORA_MOSI    44
 #define  SX126X_POWER_EN  37
+
+#define P_GPS_SDA       13  //GPS SDA pin (output option)
+#define P_GPS_SCL       14  //GPS SCL pin (output option)
+#define P_GPS_TX        16  //GPS TX pin
+#define P_GPS_RX        15  //GPS RX pin
+#define P_GPS_STANDBY_A 34  //GPS Reset/Standby pin (IO2 for socket A)
+#define P_GPS_STANDBY_C 4   //GPS Reset/Standby pin (IO4 for socket C)
+#define P_GPS_STANDBY_F 9   //GPS Reset/Standby pin (IO5 for socket F)
+#define P_GPS_1PPS      17  //GPS PPS pin
+#define GPS_BAUD_RATE   9600
+#define GPS_ADDRESS   0x42  //i2c address for GPS
  
 #define SX126X_DIO2_AS_RF_SWITCH  true
 #define SX126X_DIO3_TCXO_VOLTAGE   1.8

+ 1 - 1
variants/lilygo_tbeam_supreme_SX1262/target.cpp

@@ -336,7 +336,7 @@ bool TbeamSupSensorManager::begin() {
 }
 
 bool TbeamSupSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
-  if (requester_permissions & TELEM_PERM_LOCATION) {   // does requester have permission?
+  if (requester_permissions & TELEM_PERM_LOCATION && gps_active) {   // does requester have permission?
     telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
   }
   if (requester_permissions & TELEM_PERM_ENVIRONMENT && bme_active) {   // does requester have permission?

+ 2 - 0
variants/rak4631/platformio.ini

@@ -22,6 +22,8 @@ build_src_filter = ${nrf52840_base.build_src_filter}
 lib_deps =
   ${nrf52840_base.lib_deps}
   adafruit/Adafruit SSD1306 @ ^2.5.13
+  stevemarple/MicroNMEA @ ^2.0.6
+  sparkfun/SparkFun u-blox GNSS Arduino Library @ ^2.2.27
 
 [env:RAK_4631_Repeater]
 extends = rak4631

+ 195 - 1
variants/rak4631/target.cpp

@@ -1,6 +1,7 @@
 #include <Arduino.h>
 #include "target.h"
 #include <helpers/ArduinoHelpers.h>
+#include <helpers/sensors/MicroNMEALocationProvider.h>
 
 RAK4631Board board;
 
@@ -10,7 +11,8 @@ WRAPPER_CLASS radio_driver(radio, board);
 
 VolatileRTCClock fallback_clock;
 AutoDiscoverRTCClock rtc_clock(fallback_clock);
-SensorManager sensors;
+MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Wire);
+RAK4631SensorManager sensors = RAK4631SensorManager(nmea);
 
 #ifdef DISPLAY_CLASS
   DISPLAY_CLASS display;
@@ -20,6 +22,68 @@ SensorManager sensors;
   #define LORA_CR      5
 #endif
 
+#ifdef MESH_DEBUG
+uint32_t deviceOnline = 0x00;
+void scanDevices(TwoWire *w)
+{
+    uint8_t err, addr;
+    int nDevices = 0;
+    uint32_t start = 0;
+
+    Serial.println("Scanning I2C for Devices");
+    for (addr = 1; addr < 127; addr++) {
+        start = millis();
+        w->beginTransmission(addr); delay(2);
+        err = w->endTransmission();
+        if (err == 0) {
+            nDevices++;
+            switch (addr) {
+            case 0x42:
+                Serial.println("\tFound RAK12500 GPS Sensor");
+                deviceOnline |= RAK12500_ONLINE;
+                break;
+            default:
+                Serial.print("\tI2C device found at address 0x");
+                if (addr < 16) {
+                    Serial.print("0");
+                }
+                Serial.print(addr, HEX);
+                Serial.println(" !");
+                break;
+            }
+
+        } else if (err == 4) {
+            Serial.print("Unknow error at address 0x");
+            if (addr < 16) {
+                Serial.print("0");
+            }
+            Serial.println(addr, HEX);
+        }
+    }
+    if (nDevices == 0)
+        Serial.println("No I2C devices found\n");
+
+    Serial.println("Scan for devices is complete.");
+    Serial.println("\n");
+}
+#endif
+
+static bool readStringUntil(Stream& s, char dest[], size_t max_len, char term, unsigned int timeout_millis) {
+  unsigned long timeout = millis() + timeout_millis;
+  char *dp = dest;
+  while (millis() < timeout && dp - dest < max_len - 1) {
+    if (s.available()) {
+      char c = s.read();
+      if (c == term) break;
+      *dp++ = c;  // append to dest[]
+    } else {
+      delay(1);
+    }
+  }
+  *dp = 0;  // null terminator
+  return millis() < timeout;   // false, if timed out
+}
+
 bool radio_init() {
   rtc_clock.begin(Wire);
   
@@ -68,6 +132,136 @@ void radio_set_tx_power(uint8_t dbm) {
   radio.setOutputPower(dbm);
 }
 
+void RAK4631SensorManager::start_gps()
+{
+  //function currently not used
+  gps_active = true;
+  pinMode(disStandbyPin, OUTPUT);
+  digitalWrite(disStandbyPin, 1);
+  MESH_DEBUG_PRINTLN("GPS should be on now");
+}
+
+void RAK4631SensorManager::stop_gps()
+{
+  //function currently not used
+  gps_active = false;
+  pinMode(disStandbyPin, OUTPUT);
+  digitalWrite(disStandbyPin, 0);
+  MESH_DEBUG_PRINTLN("GPS should be off now");
+}
+
+void RAK4631SensorManager::sleep_gps() {
+  gps_active = false;
+  ublox_GNSS.powerSaveMode();
+  MESH_DEBUG_PRINTLN("GPS should be sleeping now");
+}
+
+void RAK4631SensorManager::wake_gps() {
+  gps_active = true;
+  ublox_GNSS.powerSaveMode(false);
+  MESH_DEBUG_PRINTLN("GPS should be waking now");
+}
+
+bool RAK4631SensorManager::gpsIsAwake(uint32_t ioPin){
+  
+  int pinInitialState = 0;
+
+  //set initial waking state
+  pinMode(ioPin,OUTPUT);
+  digitalWrite(ioPin,0);
+  delay(1000);
+  digitalWrite(ioPin,1);
+  delay(1000);
+
+  if (ublox_GNSS.begin(Wire) == true){
+    MESH_DEBUG_PRINTLN("GPS init correctly and GPS is turned on");
+    ublox_GNSS.setI2COutput(COM_TYPE_NMEA);
+    ublox_GNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT);
+    disStandbyPin = ioPin;
+    gps_active = true;
+    gps_present = true;
+    return true;
+  }
+  else
+  MESH_DEBUG_PRINTLN("GPS failed to init on this IO pin... try the next");
+  //digitalWrite(ioPin,pinInitialState); //reset the IO pin to initial state
+  return false;
+}
+
+bool RAK4631SensorManager::begin() {
+  
+  #ifdef MESH_DEBUG
+  scanDevices(&Wire);
+  #endif
+
+  //search for the correct IO standby pin depending on socket used
+  if(gpsIsAwake(P_GPS_STANDBY_A)){
+    MESH_DEBUG_PRINTLN("GPS is on socket A");
+  }
+  else if(gpsIsAwake(P_GPS_STANDBY_C)){
+    MESH_DEBUG_PRINTLN("GPS is on socket C"); 
+  }
+  else if(gpsIsAwake(P_GPS_STANDBY_F)){
+    MESH_DEBUG_PRINTLN("GPS is on socket F"); 
+  }
+  else{
+    MESH_DEBUG_PRINTLN("Error: No GPS found on sockets A, C or F"); 
+    gps_active = false;
+    gps_present = false;
+    return false;
+  }
+
+  //Now that GPS is found and set up, set to sleep for initial state
+  stop_gps();
+}
+
+bool RAK4631SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
+  if (requester_permissions & TELEM_PERM_LOCATION && gps_active) {   // does requester have permission?
+    telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
+  }
+  return true;
+}
+
+void RAK4631SensorManager::loop() {
+  static long next_update = 0;
+  
+  _nmea->loop();
+
+  if (millis() > next_update && gps_active) {
+    node_lat = (double)ublox_GNSS.getLatitude()/10000000.;
+    node_lon = (double)ublox_GNSS.getLongitude()/10000000.;
+    node_altitude = (double)ublox_GNSS.getAltitude()/1000.;
+    MESH_DEBUG_PRINT("lat %f lon %f alt %f\r\n", node_lat, node_lon, node_altitude);
+    
+    next_update = millis() + 1000;
+  }
+}
+
+int RAK4631SensorManager::getNumSettings() const { return 1; }  // just one supported: "gps" (power switch)
+
+const char* RAK4631SensorManager::getSettingName(int i) const {
+  return i == 0 ? "gps" : NULL;
+}
+
+const char* RAK4631SensorManager::getSettingValue(int i) const {
+  if (i == 0) {
+    return gps_active ? "1" : "0";
+  }
+  return NULL;
+}
+
+bool RAK4631SensorManager::setSettingValue(const char* name, const char* value) {
+  if (strcmp(name, "gps") == 0) {
+    if (strcmp(value, "0") == 0) {
+      stop_gps();
+    } else {
+      start_gps();
+    }
+    return true;
+  }
+  return false;  // not supported
+}
+
 mesh::LocalIdentity radio_new_identity() {
   RadioNoiseListener rng(radio);
   return mesh::LocalIdentity(&rng);  // create new random identity

+ 47 - 1
variants/rak4631/target.h

@@ -7,19 +7,65 @@
 #include <helpers/CustomSX1262Wrapper.h>
 #include <helpers/AutoDiscoverRTCClock.h>
 #include <helpers/SensorManager.h>
+#include <helpers/sensors/LocationProvider.h>
+#include <SparkFun_u-blox_GNSS_Arduino_Library.h>
 #ifdef DISPLAY_CLASS
   #include <helpers/ui/SSD1306Display.h>
 #endif
 
+#define _BV(x)   (1 << x)
+
+class RAK4631SensorManager: public SensorManager {
+    bool gps_active = false;
+    bool gps_present = false;
+    LocationProvider * _nmea;
+    SFE_UBLOX_GNSS ublox_GNSS;
+    uint32_t disStandbyPin = 0;
+  
+    void start_gps();
+    void stop_gps();
+    void sleep_gps();
+    void wake_gps();
+    bool gpsIsAwake(uint32_t ioPin);
+
+  public:
+    RAK4631SensorManager(LocationProvider &nmea): _nmea(&nmea) { }
+    bool begin() override;
+    bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override;
+    void loop() override;
+    int getNumSettings() const override;
+    const char* getSettingName(int i) const override;
+    const char* getSettingValue(int i) const override;
+    bool setSettingValue(const char* name, const char* value) override;
+  };
+
 extern RAK4631Board board;
 extern WRAPPER_CLASS radio_driver;
 extern AutoDiscoverRTCClock rtc_clock;
-extern SensorManager sensors;
+extern RAK4631SensorManager sensors;
 
 #ifdef DISPLAY_CLASS
   extern DISPLAY_CLASS display;
 #endif
 
+enum {
+  POWERMANAGE_ONLINE  = _BV(0),
+  DISPLAY_ONLINE      = _BV(1),
+  RADIO_ONLINE        = _BV(2),
+  GPS_ONLINE          = _BV(3),
+  PSRAM_ONLINE        = _BV(4),
+  SDCARD_ONLINE       = _BV(5),
+  AXDL345_ONLINE      = _BV(6),
+  BME280_ONLINE       = _BV(7),
+  BMP280_ONLINE       = _BV(8),
+  BME680_ONLINE       = _BV(9),
+  QMC6310_ONLINE      = _BV(10),
+  QMI8658_ONLINE      = _BV(11),
+  PCF8563_ONLINE      = _BV(12),
+  OSC32768_ONLINE     = _BV(13),
+  RAK12500_ONLINE     = _BV(14),
+};
+
 bool radio_init();
 uint32_t radio_get_rng_seed();
 void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);