A controller-neutral API for working with GPS devices.

Dependents:   CsrLocationDemo CsrLocationDemo

Revision:
1:c1122f8eec82
Parent:
0:792e9343fd39
Child:
4:f35227b1f341
Child:
5:900c3ab6c090
--- a/GPSProvider.h	Thu Oct 30 14:42:27 2014 +0000
+++ b/GPSProvider.h	Fri Oct 31 13:34:59 2014 +0000
@@ -21,14 +21,11 @@
 extern GPSProviderImplBase *createGPSProviderInstance(void);
 
 //
-// Here's a snippet showing how this API can be used. Please note that this is
-// an asynchronous API--users can setup an asynchronous handler to receive
-// location updates. The handler gets invoked from interrupt context. Users
-// *should not* do any long running or blocking operations in the handler.
+// Here's a snippet showing how this API can be used. The handler gets invoked
+// from thread context--i.e. from the main application.
 //
-//      void handleGPSData(const LocationUpdateParams_t *newData) {
-//          /* Do something with the location update; but please don't make any
-//           * blocking calls or invoke long-running operations. */
+//      void handleGPSData(const LocationUpdateParams_t *newLocation) {
+//          ...
 //      }
 //
 //      GPSProvider gps;
@@ -36,30 +33,35 @@
 //      gps.setPowerMode(LOW_POWER);
 //      gps.onLocationUpdate(handleGPSData);
 //
-//      gps.reset(); // implicitly calls powerOn().
+//      gps.reset();
 //      gps.start();
 //
-//      wait(/* some duration to allow controller to stabilize */);
-//      if (gps.haveDeviceInfo()) {
-//          printf("%s", gps.getDeviceInfo());
-//      }
+//      while (true) {
+//          /* purely optional */
+//          static bool printedDeviceInfo = false;
+//          if (!printedDeviceInfo && gps.haveDeviceInfo()) {
+//              printf("%s", gps.getDeviceInfo());
+//              printedDeviceInfo = true;
+//          }
 //
-//      ...
-//      /* Period where the gps locationHandler gets invoked asynchronously. */
-//      ...
+//          /* Main message processing activity; location callbacks are called
+//           * as a result of message processing. */
+//          gps.process();
+//          /* sleep(); */
 //
-//      /* at some point in the future, either the following.. */
+//          if (/* at some point in the future */) {
+//              break;
+//          }
+//      }
 //      gps.stop();
-//      gps.powerOff();
-//      /* or simply destroy the gps object to achieve the same. */
 //
 
 class GPSProvider {
 public:
     /** Power mode selection */
     enum PowerMode_t {
-         POWER_FULL,
-         POWER_LOW,
+         POWER_FULL, /**< full-power mode typically results in high-accuracy location data updated at 1Hz. */
+         POWER_LOW,  /**< low-power mode involves longer periods of hibernation in between location updates. */
     };
 
     /**
@@ -82,10 +84,14 @@
     struct LocationUpdateParams_t {
         uint32_t       version; /* Layout-version for the following structure;
                                  * this is to accommodate changes over time. */
+        bool           valid;   /* Does this update contain a valid location. */
         LocationType_t lat;
         LocationType_t lon;
         Altitude_t     altitude;
 
+        unsigned       numGPSSVs; /* num GPS Satellites */
+        unsigned       numGLOSVs; /* num GLONASS Satellites */
+
         union {
             GPSTime_t gpsTime;
             float     utcTime;
@@ -134,20 +140,48 @@
     void stop(void);
 
     /**
+     * Process location data from chip and update location and satellite
+     * information. This API is supposed to be called repeatedly from the
+     * application in thread mode to process incoming messages as they are
+     * received from the GPS controller. Arriving data is first appended to
+     * something like a circular buffer by interrupts, and then parsed as
+     * messages in thread mode.
+     *
+     * The application typically enters a loop calling process() after
+     * initializing the GPS controller with start(). process() returns
+     * immediately if there is no work to be done, but it must get invoked
+     * frequently in order to keep pace with arriving data.
+     *
+     * Mbed's sleep() may be usefully thrown into the application's process()
+     * loop to save power--sleep() has the effect of putting the processor to
+     * sleep while waiting for an event (such as an interrupt). As always, some
+     * care must be taken in employing sleep(), because there is a small
+     * synchronization window where an interrupt may arrive and pend data which
+     * doesn't get processed (as illustrated below).
+     *
+     *  while (true) {
+     *      process();
+     *        <--  interrupt arrives now and appends new data
+     *      sleep(); // but then we go to sleep without processing it.
+     *  }
+     *
+     * There is a way around it: if sleep() boils down to the use of ARM's WFE
+     * instruction (as opposed to WFI), then its safe from the above-mentioned
+     * synchronization window.
+     */
+    void process(void);
+
+    /**
      * @return  true if the initialization process has received enough
      *     information to determine the hardware's version/device-info.
      */
-    bool haveDeviceInfo(void) const {
-        return discoveredDeviceInfo;
-    }
+    bool haveDeviceInfo(void) const;
 
     /**
      * Fetch the device information string. This is expected to contain the
      * version number or any other device identifier.
      */
-    const char *getDeviceInfo(void) const {
-        return deviceInfo;
-    }
+    const char *getDeviceInfo(void) const;
 
     /**
      * This is a wildcard API for sending controller specific commands. Use of
@@ -166,16 +200,12 @@
      *
      * @Note: This is cleared after reset().
      */
-    bool locationAvailable(void) const {
-        return haveValidLocation;
-    }
+    bool locationAvailable(void) const;
 
     /**
      * @return  the last valid location if there is any; else NULL.
      */
-    const LocationUpdateParams_t *getLastLocation(void) const {
-        return haveValidLocation ? &lastLocation : NULL;
-    }
+    const LocationUpdateParams_t *getLastLocation(void) const;
 
     /**
      * Type declaration for a callback to be invoked from interrupt context upon
@@ -196,17 +226,21 @@
      */
     void onLocationUpdate(LocationUpdateCallback_t callback);
 
+    /**
+     * In low-power operation, the GPS controller may be expected to hibernate
+     * for extended periods and location updates may be infrequent. It should
+     * then be possible for an application to demand location data when needed.
+     *
+     * This calls results in a locationCallback if there is a useful location to
+     * report.
+     */
+    void lpmGetImmediateLocation(void);
+
 public:
     /**
      * Default constructor.
      */
-    GPSProvider() :
-        impl(createGPSProviderInstance()),
-        havePoweredOn(false),
-        discoveredDeviceInfo(false),
-        haveValidLocation(false),
-        deviceInfo(NULL),
-        updateCallback(NULL) {
+    GPSProvider() : impl(createGPSProviderInstance()) {
         /* empty */
     }
 
@@ -224,15 +258,6 @@
      */
     GPSProviderImplBase *const impl;
 
-private:
-    bool                      havePoweredOn;
-    bool                      discoveredDeviceInfo;
-    bool                      haveValidLocation;
-
-    const char               *deviceInfo;
-    LocationUpdateParams_t    lastLocation;
-    LocationUpdateCallback_t *updateCallback;
-
     /* disallow copy constructor and assignment operators */
 private:
     GPSProvider(const GPSProvider&);