GPS4Palm

Source Code Documentation


GPS.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * $RCSfile: GPS_8c-source.html,v $
00004  *
00005  * GPS4Palm Main functions
00006  * (PilotMain, AppStart, AppStop, EventLoop, ApplicationHandleEvent and others)
00007  *
00008  * Based on the example "GPS" from the book
00009  * "Palm Programming, the Developer's Guide, 2nd edition"
00010  * by O'Reilly.
00011  * (Copyright (c) 1998-2001, Neil Rhodes and Julie McKeehan  neil@pobox.com)
00012  *
00013  * This program is Copyright (C) 03/2003 Matthias Prinke
00014  * <matthias.prinke@surfeu.de> and covered by GNU's GPL.
00015  * In particular, this program is free software and comes WITHOUT
00016  * ANY WARRANTY.
00017  *
00018  * $Author: mp $
00019  *
00020  * $Date: 2007-10-08 20:40:33 $
00021  *
00022  * $Revision: 1.7.2.1 $
00023  *
00024  * $Log: GPS_8c-source.html,v $
00024  * Revision 1.7.2.1  2007-10-08 20:40:33  mp
00024  * updated for gps4palm V0.9.5 beta
00024  *
00025  * Revision 1.49  2005-05-28 10:15:46  mp
00026  * fixed check for gpslib
00027  *
00028  * Revision 1.48  2005/05/13 18:31:30  mp
00029  * removed variables filename and gAutoPwrOff
00030  *
00031  * Revision 1.47  2005/05/06 13:32:59  mp
00032  * moved Bluetooth code to Serial.c
00033  *
00034  * Revision 1.46  2005/04/24 14:09:05  mp
00035  * fixed comment
00036  *
00037  * Revision 1.45  2005/04/20 20:58:25  mp
00038  * implemented opening of Bluetooth Virtual Serial Port
00039  * with connecting to known device (address)
00040  *
00041  * Revision 1.44  2005/04/08 14:45:28  mp
00042  * added check for High-Density Display Feature Set
00043  *
00044  * Revision 1.43  2005/03/24 09:18:36  mp
00045  * added check for FiveWay controller
00046  *
00047  * Revision 1.42  2005/02/26 14:55:19  mp
00048  * fixed doxygen-tags
00049  *
00050  * Revision 1.41  2005/02/26 14:51:04  mp
00051  * added 3.5 New Feature Set availability check
00052  *
00053  * Revision 1.40  2005/02/19 20:04:12  mp
00054  * changed filename[32] to filename[FILENAMEMAXLEN]
00055  *
00056  * Revision 1.39  2005/02/19 14:37:42  mp
00057  * moved checking VFS Feature Set from FileselForm.c
00058  *
00059  * Revision 1.38  2005/02/06 15:02:00  mp
00060  * added RTS serial mux control with SrmControl()
00061  *
00062  * Revision 1.37  2005/02/05 17:35:47  mp
00063  * added deletion of orphaned tracks, improved serial port handling
00064  *
00065  * Revision 1.36  2004/12/09 17:24:44  mp
00066  * added form switching with hard keys
00067  *
00068  * Revision 1.35  2004/12/07 17:15:02  mp
00069  * added closing of track DB upon application stop
00070  *
00071  * Revision 1.34  2004/12/04 09:37:18  mp
00072  * modified default Active Track preferences
00073  *
00074  * Revision 1.33  2004/12/02 23:00:38  mp
00075  * added default values for gPrefs.act_trk to application preferences
00076  *
00077  * Revision 1.32  2004/12/01 17:45:43  mp
00078  * added default values for track log preferences
00079  *
00080  * Revision 1.31  2004/11/30 21:04:01  mp
00081  * added TrackForm event handler, modified DB open/close
00082  *
00083  * Revision 1.30  2004/11/25 20:05:51  mp
00084  * added ApproachForm event handler and default settings
00085  *
00086  * Revision 1.29  2004/11/24 21:10:40  mp
00087  * moved static function declarations from header to implementation file,
00088  * added AboutForm event handler function
00089  *
00090  * Revision 1.28  2004/11/23 17:51:23  mp
00091  * removed unused variables, added missing return value
00092  *
00093  * Revision 1.27  2004/11/20 15:55:31  mp
00094  * added deletion of invalid Route DB
00095  *
00096  * Revision 1.26  2004/11/19 17:55:09  mp
00097  * added initialization of gPrefs.auto_wpt
00098  *
00099  * Revision 1.25  2004/11/13 15:54:36  mp
00100  * reordered includes, added RouteEditForm
00101  *
00102  * Revision 1.24  2004/11/11 21:38:01  mp
00103  * added default assignement for Active Route
00104  *
00105  * Revision 1.23  2004/04/29 17:42:09  mp
00106  * added RouteForm, modified for doxygen
00107  *
00108  * Revision 1.22  2004/04/27 18:55:25  mp
00109  * added opening of route DB
00110  *
00111  * Revision 1.21  2004/04/22 18:39:18  mp
00112  * added check for gpslib
00113  *
00114  * Revision 1.20  2004/04/17 12:46:13  mp
00115  * moved kBaudRate to Serial.h, added gpslib.h
00116  *
00117  * Revision 1.19  2004/04/06 20:39:02  mp
00118  * corrected preferences version check in AppStart()
00119  *
00120  * Revision 1.18  2004/03/20 13:37:52  mp
00121  * added call of FrmCloseAllForms() to AppStop()
00122  *
00123  * Revision 1.17  2004/03/13 15:00:17  mp
00124  * added clearing of NavigationForm TimeField in case of no GPS
00125  *
00126  * Revision 1.16  2004/03/13 14:08:25  mp
00127  * added update of gGPSData.valid in case of no GPS
00128  *
00129  * Revision 1.15  2004/03/13 12:39:15  mp
00130  * moved call of Set_UTM_Parameters() to AppStart()
00131  *
00132  * Revision 1.14  2004/03/12 20:56:22  mp
00133  * added call of init_radius() to AppStart()
00134  *
00135  * Revision 1.13  2004/03/10 17:24:15  mp
00136  * added gPrefs.act_wpt.valid to preferences
00137  *
00138  * Revision 1.12  2004/03/09 19:07:21  mp
00139  * Cleaned up/added comments to #include directives.
00140  *
00141  * Revision 1.11  2004/03/07 14:23:18  mp
00142  * added waypoint database open/close
00143  *
00144  * Revision 1.10  2004/03/03 19:03:58  mp
00145  * added WayptEditForm event handler
00146  *
00147  * Revision 1.9  2004/03/01 17:22:15  mp
00148  * Fixed selection of connection profile (if New Serial Manager present).
00149  *
00150  * Revision 1.8  2003/12/30 20:19:54  mp
00151  * added MathLib
00152  *
00153  * Revision 1.7  2003/12/01 20:12:53  mp
00154  * added default values for new application preferences
00155  *
00156  * Revision 1.6  2003/11/20 20:42:45  mp
00157  * added event handler for MapOptsForm, added some Preferences defaults
00158  *
00159  * Revision 1.5  2003/11/18 18:44:25  mp
00160  * Added current Form and Auto Power-Off status to Application Preferences.
00161  * Implemented switch to previous form (stored in Preferences) at
00162  *   application start.
00163  * Cleaned up code and added comments.
00164  *
00165  * Revision 1.4  2003/10/20 17:15:10  mp
00166  * removed gShowingLostSatellite, changed 'No GPS' status display to
00167  * UpdateStatus(), changed SetFieldTextFromStr() to SetFieldText()
00168  *
00169  * Revision 1.3  2003/10/18 16:18:12  mp
00170  * added FileSelForm, added load/save of preferences
00171  *
00172  * Revision 1.2  2003/10/15 19:07:54  mp
00173  * moved HandleMessage etc. to HandleMessage.c
00174  *
00175  * Revision 1.1.1.1  2003/07/14 18:59:29  mp
00176  * Imported GPS4Palm to CVS revision control.
00177  *
00178  *
00179  ****************************************************************************/
00180 #include <PalmOS.h>
00181 #include <PalmCompatibility.h>
00182 #include <Extensions/ExpansionMgr/VFSMgr.h>
00183 #ifdef HAVE_FIVEWAY_SDK
00184 #include <palmOne_68K.h>
00185 #endif
00186 #include <SerialMgrOld.h>
00187 #include "GPS.h"
00188 #include "Data.h"               /* Waypoint DB create/open/close */
00189 #include "ResourceDefines.h"    /* Resource IDs */
00190 #include "MathLib.h"            /* MathLib Find/Open/Close/Remove */
00191 #include "gpslib.h"             /* GPS I/O library */
00192 #include "HandleMessage.h"      /* UpdateStatus(), HandleMessage() */
00193 #include "MainForm.h"           /* MainFormHandleEvent() */
00194 #include "PortForm.h"           /* PortFormHandleEvent() */
00195 #include "SkyviewForm.h"        /* SkyviewFormHandleEvent() */
00196 #include "NavigationForm.h"     /* NavigationFormHandleEvent() */
00197 #include "FileselForm.h"        /* FileSelFormHandleEvent() */
00198 #include "MiscOptsForm.h"       /* MiscOptsFormHandleEvent() */
00199 #include "MapOptsForm.h"        /* MapOptsFormHandleEvent() */
00200 #include "WaypointForm.h"       /* WaypointFormHandleEvent() */
00201 #include "WayptEditForm.h"      /* WayptEditFormHandleEvent() */
00202 #include "RouteForm.h"          /* RouteFormHandleEvent() */
00203 #include "RouteEditForm.h"      /* RouteEditFormHandleEvent() */
00204 #include "TrackForm.h"          /* TrackFormHandleEvent() */
00205 #include "AboutForm.h"          /* AboutFormHandleEvent() */
00206 #include "ApproachForm.h"       /* ApproachFormHandleEvent() */
00207 #include "DebugForm.h"          /* DebugFormHandleEvent() */
00208 #include "MapForm.h"            /* MapFormHandleEvent */
00209 #include "Utils.h"              /* misc. */
00210 #include "Serial.h"             /* Serial Manager/New Serial Manager wrappers */
00211 #include "geo.h"                /* Geodesic/Geometric Utility Functions */
00212 #include "utm.h"                /* Set_UTM_Parameters() */
00213 #include "common.h"
00214 
00215 /** Minimum Version for 2.0 Capabilities */
00216 #define kOS20MinVersion         0x02003000      
00217 
00218 /** Minimum PalmOS Version */
00219 #define kMinimumVersion 0x03000000
00220 
00221 /** Minimum Version for 3.5 New Feature Set */
00222 #define kOS35MinVersion         0x03503000      
00223 
00224 #define GpsLibName      "gpslib"
00225 
00226 
00227 /* #define USE_HARD_KEYS */     /* set define to switch main forms with keys */  
00228 
00229 
00230 /* ---------------------------------------- */
00231 /* Global timing variables (initialization) */
00232 /* ---------------------------------------- */
00233 
00234 /** tickCount of last time we read data from GPS */
00235 UInt32          gLastSuccessfulReception = 0;           
00236 
00237 /** tickCount of last time we displayed GPS data on the Palm device */
00238 UInt32          gLastTimeDisplay = 0;
00239 
00240 /** tickCount of the next scheduled read */
00241 UInt32          gNextReadTime = 0;
00242 
00243 
00244 #ifdef DEBUG_FORM
00245 /* Start of Debugging */
00246 
00247 /* number of checksum errors */
00248 UInt32          gChkErrs = 0; 
00249 
00250 /* minimum number of characters received */
00251 UInt32          gMinReceived = 0xFFFFFFFF;
00252 
00253 /* maximum number of characters received */
00254 UInt32          gMaxReceived = 0;
00255 
00256 /* End   of Debugging */
00257 #endif
00258 
00259 /** Global flag */
00260 Boolean gFormOpened = false;
00261 
00262 /** VFS Feature Set available */
00263 Boolean gVfsManagerFtr;
00264 
00265 /** OS 3.5 Feature Set available */
00266 Boolean gFtrSet35;
00267 
00268 /** High-Density Display Feature Set available */
00269 Boolean gHdFtrSet;
00270 
00271 /** FiveWay Controller available */
00272 Boolean         gFiveWayAvail;
00273 static Boolean  haveFiveWay = false;
00274 
00275 /* GPS Data */
00276 extern GPSType gGPSData;
00277 
00278 /** Preferences data structure */
00279 PrefsType gPrefs;
00280 
00281 /* four-character port name or logical port number (New Serial Manager) */
00282 extern UInt32 gSerialPort;
00283 
00284 /* Variables used by Connection Manager */
00285 extern Char **gProfiles;
00286 extern UInt16 gNumProfiles;
00287 
00288 
00289 /* ------------------------------------- */
00290 /* Global timing variables (declaration) */
00291 /* ------------------------------------- */
00292 
00293 /** Ticks per second (OS/Hardware specific) */
00294 UInt16 gTicksPerSecond;
00295 
00296 /**
00297  *  if we go this long without updating the time
00298  *  then update as soon as we get a valid time
00299  *  (without waiting for an even 5-second time)
00300  */
00301 UInt32 gMaxTicksWithoutTime;
00302 
00303 /**
00304  *  if we go this long without communicating with GPS,
00305  *  we've lost it and need to notify the user
00306  */
00307 UInt32  gTicksToLoseGPS;
00308 
00309 /* Static Functions */
00310 static Err AppStart(void);
00311 static void AppStop(void);
00312 static void OS2(void);
00313 static Boolean HaveFiveWay(void);
00314 static Boolean ApplicationHandleEvent(EventPtr event);
00315 static void EventLoop(void);
00316 static long TimeUntilNextRead(void);
00317 static void WarnUserIfHaventHeardFromGPSRecently(void)  MSGHANDLER_SECTION;
00318 static UInt32 WaitForData(UInt32 bufferSize)            MSGHANDLER_SECTION;
00319 static Boolean ReadAvailableData(Char *data,
00320   UInt32 bufferSize, UInt32 numBytesPending)            MSGHANDLER_SECTION;
00321 
00322 
00323 /****************************************************************************
00324  *
00325  * FUNCTION:    AppStart
00326  *
00327  * DESCRIPTION: Loads Application Preferences.
00328  *              Checks if Serial Library is available and opens serial port,
00329  *              checks if Math Library is available and
00330  *              shows appropriate error message on failure.
00331  *              Initializes timing parameters and enables serial port mux.
00332  *
00333  * GLOBALS:     gPrefs                  -- Application Preferences
00334  *              gWaypointDB             -- Waypoint Database reference
00335  *              gNewSerialManager       -- New Serial Manager present
00336  *              gPortID                 -- Serial Port ID
00337  ****************************************************************************/
00338 static 
00339 Err AppStart(void)
00340 {
00341   UInt32        vfsMgrVersion;                  /* VFS Manager Version */
00342   UInt32        version;                        /* feature version no. */
00343   UInt16        prefsSize;                      /* preferences struct size */
00344   Int16         prefsVersion = noPreferenceFound;
00345   UInt16        cnc_index;                      /* CncMgr profile index */
00346   UInt32        host_port;                      /* Host serial port */
00347   Err           err = 0;                        /* error code */
00348   Boolean       created;                        /* flag: DB created */  
00349   LocalID       dbID;                           /* local DB ID */
00350   
00351   prefsSize = sizeof(PrefsType);
00352 
00353   /* Get Application Preferences (unsaved) */
00354   prefsVersion = PrefGetAppPreferences(kCreatorId, kPrefsId, &gPrefs,
00355      &prefsSize, false);
00356 
00357   if ( (prefsVersion != kVersion) || (prefsVersion == noPreferenceFound) ) {
00358     /* no preferences or wrong version: set defaults */ 
00359     StrCopy(gPrefs.filename, "");
00360     gPrefs.mag = 1;
00361     gPrefs.xofs = 0;
00362     gPrefs.yofs = 0;
00363     gPrefs.dx = 0;
00364     gPrefs.dy = 0;
00365     gPrefs.dw = 0;
00366     gPrefs.dh = 0;
00367     gPrefs.form = GPSMainForm;
00368     gPrefs.pwroff = AUTOPWROFF;
00369     gPrefs.auto_wpt = true;
00370     gPrefs.approach_alert = true;               /* Approach alert form        */
00371     gPrefs.approach_sound = true;               /* Approach alert sound       */
00372     gPrefs.serprefs.gps_port = 0;               /* GPS serial port/CncMgr ID  */ 
00373     gPrefs.serprefs.host_port = 0;              /* Host serial port/CncMgrID  */
00374     gPrefs.serprefs.rts_ctrl = false;           /* Multiplexer control by RTS */
00375     gPrefs.trk_log.mode = 0;                    /* Track Log Mode:      Dist. */
00376     gPrefs.trk_log.ival = 0;                    /* Track Log Interval:  10 m  */
00377     gPrefs.trk_log.wrap = 0;                    /* Track Log Full:      stop  */
00378     gPrefs.units.pos_unit = POS_D;              /* Position format:     DD.DDD° */
00379     gPrefs.units.dst_unit = DST_KM;             /* Distance unit:       km      */
00380     gPrefs.units.alt_unit = ALT_M;              /* Altitude unit:       m       */
00381     gPrefs.units.spd_unit = SPD_KMH;            /* Speed unit:          km/h    */
00382     gPrefs.mapprefs.scale = 20000;              /* Map scale:           20.000  */
00383     gPrefs.mapprefs.download = DLD_A;           /* Map download policy: auto    */
00384     gPrefs.mapprefs.select = SEL_AUTO;          /* Map selection:       auto    */
00385     gPrefs.mapprefs.fetch = FETCH_READY;        /* FetchMap state:      ready   */
00386     gPrefs.act_wpt.valid = false;               /* Active waypoint:     n/a     */
00387     gPrefs.act_rte.valid = false;               /* Active route:        n/a     */
00388     gPrefs.act_trk.valid = false;               /* Active track:        n/a     */ 
00389     gPrefs.act_trk.log_state = false;           /* Active track log:    off     */
00390   }
00391 
00392   /* check if VFS Manager Feature Set is available */
00393   err = FtrGet(sysFileCVFSMgr, vfsFtrIDVersion, &vfsMgrVersion);
00394   gVfsManagerFtr = (err == 0) ? true : false; 
00395   err = 0;
00396 
00397   /* check if High-Density Display Feature Set is available */
00398   gHdFtrSet = (FtrGet(sysFtrCreator, sysFtrNumWinVersion, &version) == 0) &&
00399                 (version >= 4);
00400 
00401   if (GetRomVersion() >= kOS20MinVersion) {
00402     /* PalmOS 2.x or higher specific operations */
00403     OS2();
00404   }
00405 
00406   gFiveWayAvail = HaveFiveWay();
00407   
00408   gFtrSet35 = (GetRomVersion() < kOS35MinVersion) ? false : true;
00409 
00410   err = OpenOrCreateDB(&gWaypointDB, kWaypointDBType /* type */,
00411     kCreatorId /* creator */, dmModeReadWrite, 0 /* cardNo */,
00412     kWaypointDBName /* name */, &created);
00413 
00414   if (created) {
00415     InitializeWaypoints();
00416   
00417     /*
00418      * If a new Waypoint DB has been created, the Route DB
00419      * (if any exists) is invalid and must be deleted.
00420      */
00421      dbID = DmFindDatabase(0 /* cardNo */, kRouteDBName);
00422      
00423      if (dbID) {
00424        DmDeleteDatabase(0 /* cardNo */, dbID);
00425      }
00426   }
00427   
00428   err = OpenOrCreateDB(&gRouteDB, kRouteDBType /* type */,
00429     kCreatorId /* creator */, dmModeReadWrite, 0 /* cardNo */,
00430     kRouteDBName /* name */, &created);
00431 
00432   err = OpenOrCreateDB(&gTrackHdrDB, kTrkHdrDBType /* type */,
00433     kCreatorId /* creator */, dmModeReadWrite, 0 /* cardNo */,
00434     kTrkHdrDBName /* name */, &created);
00435   
00436   /* if created, delete all tracks */
00437   if (created) {
00438     DeleteTracks();
00439   }
00440   
00441   err = Set_UTM_Parameters(     SEMIMAJOR_AXIS,
00442                                 FLATTENING,
00443                                 0 /* Override_Zone */);
00444 
00445   if (err != UTM_NO_ERROR)
00446      return err;
00447 
00448   dbID = DmFindDatabase(0, "gpslib");
00449   if ( !dbID ) {
00450     FrmAlert(NoGpslibAlert);
00451     return sysErrLibNotFound;
00452   }
00453 
00454   /* check if New Serial Manager is available */
00455   gNewSerialManager = (FtrGet(sysFileCSerialMgr,
00456     sysFtrNewSerialPresent, &version) == 0) && (version != 0);
00457   
00458   /* check if Connection Manager feature set is available */
00459   gCncManagerFtr = (FtrGet(kCncFtrCncMgrCreator,
00460     kCncFtrCncMgrVersion, &version) == 0) && (version >= 0x00040001);
00461   
00462   if (gNewSerialManager) {
00463     if (gCncManagerFtr) {
00464     
00465       /* get GPS Connection Manager profile ID from preferences */
00466       if (CncProfileGetIndex(gPrefs.serprefs.gps_port, &cnc_index) == errNone) {
00467 
00468         /* get list of Connection Manager profiles */
00469         err = CncGetProfileList(&gProfiles, &gNumProfiles);
00470 
00471         if (!err) {
00472           /* get port name and baud rate from current profile */
00473           err = CncGetProfileInfo(gProfiles[cnc_index],
00474             &gSerialPort, &gPrefs.serprefs.gps_baud, 0, 0, 0, 0, 0, 0);                 
00475 
00476           /* free Connection Manager profile list */
00477           FreeCncProfileList();
00478         }
00479       }
00480 
00481       /* get Host Connection Manager profile ID from preferences */
00482       if (CncProfileGetIndex(gPrefs.serprefs.host_port, &cnc_index) == errNone) {
00483 
00484         /* get list of Connection Manager profiles */
00485         err = CncGetProfileList(&gProfiles, &gNumProfiles);
00486 
00487         if (!err) {
00488           /* get port name and baud rate from current profile */
00489           err = CncGetProfileInfo(gProfiles[cnc_index],
00490             &host_port, &gPrefs.serprefs.host_baud, 0, 0, 0, 0, 0, 0);                  
00491 
00492           /* free Connection Manager profile list */
00493           FreeCncProfileList();
00494         }
00495       }
00496 
00497     } else {
00498       /* no Connection Managere feature set available */
00499       if (gPrefs.serprefs.gps_port)
00500         gSerialPort = gPrefs.serprefs.gps_port;
00501         
00502       if (gPrefs.serprefs.host_port)
00503         host_port = gPrefs.serprefs.host_port;
00504     }
00505         
00506     if (!err) {
00507       /*
00508        * Note:
00509        * -----
00510        * We do not try to open the host port now, because
00511        * some interfaces (IrDA, Bluetooth) have to be enabled first,
00512        * but should be disabled to save power until they are
00513        * really needed.
00514        */
00515        
00516       /* set Serial Port to be used by gpslib */
00517       GpslibSetSerialPort(host_port);
00518       
00519       /* open GPS port */
00520       if (gSerialPort == sysFileCVirtRfComm) {
00521         /*
00522          * Bluetooth Virtual Serial Port --
00523          * Connect to known device (address)
00524          */
00525         err = BluetoothOpen(gSerialPort, gPrefs.serprefs.gps_baud,
00526           gPrefs.serprefs.gps_btaddr, &gPortID);
00527 
00528       } else {
00529         /* open non-BT serial port */
00530         err = SrmOpen(gSerialPort, gPrefs.serprefs.gps_baud, &gPortID);
00531       }
00532     }
00533     
00534     if (!err) {
00535       FrmGotoForm(gPrefs.form);    
00536     } else { 
00537       err = 0;
00538       FrmGotoForm(GPSPortForm);
00539     }
00540 
00541   } else {
00542     /* use default settings */
00543     err = SysLibFind("Serial Library", &gPortID);
00544     if (err == 0)
00545       err = SerOpen(gPortID, 0, kBaudRate);
00546 
00547     if (err == serErrAlreadyOpen) {
00548       FrmAlert(SerialInUseAlert);
00549       DoClose(gPortID);
00550     } else if (err) {
00551       FrmAlert(CantOpenSerialAlert);
00552     } else {
00553       err = DoSetReceiveBuffer(gPortID, gSerialBuffer,
00554         sizeof(gSerialBuffer));
00555       FrmGotoForm(gPrefs.form);
00556     }
00557   }
00558 
00559   if (!err) {
00560     err = SysLibFind(MathLibName, &MathLibRef);
00561     if (err)
00562       err = SysLibLoad(LibType, MathLibCreator, &MathLibRef);
00563     
00564     if (err) {
00565       FrmAlert(NoMathLibAlert);
00566       DoClose(gPortID);
00567     } else {
00568       err = MathLibOpen(MathLibRef, MathLibVersion);
00569     
00570       if (err) {
00571         FrmAlert(NoMathLibAlert);
00572         DoClose(gPortID);
00573       }
00574     }
00575   }
00576   
00577   if (!err) {
00578     /* Initialize lookup table earth_radius[latitude] */
00579     init_radius();
00580 
00581 #if defined(SERMUX_VISOR_HS) | \
00582     defined(SERMUX_VISOR_KBD) | \
00583     defined(SERMUX_PALMIII_RTS)
00584     sermux_enable(true);
00585 #else
00586     sermux_enable(gPrefs.serprefs.rts_ctrl);
00587 #endif
00588     sermux_select(false);
00589 
00590     
00591     gTicksPerSecond = SysTicksPerSecond();
00592     gMaxTicksWithoutTime = 6 * gTicksPerSecond;
00593     gTicksToLoseGPS = 15 * gTicksPerSecond;
00594   }
00595   
00596   return err;
00597 }
00598 
00599 /*****************************************************************************
00600  * FUNCTION:    AppStop
00601  *
00602  * DESCRIPTION: Restores serial buffer size and closes serial port.
00603  *              Disables serial port mux.
00604  *              Saves Application Preferences. 
00605  *
00606  ****************************************************************************/
00607 static void AppStop(void)
00608 {
00609   Int   usecount;
00610   Err   err;
00611 
00612   FrmCloseAllForms();
00613   
00614   /* Close Waypoint Database */
00615   err = DmCloseDatabase(gWaypointDB);
00616 
00617   /* Close Route Database */
00618   err = DmCloseDatabase(gRouteDB);
00619 
00620   /* Close Track Header Database */
00621   err = DmCloseDatabase(gTrackHdrDB);
00622 
00623   /* Close Track Point Database (if open) */
00624   if (gTrackDB)
00625     err = DmCloseDatabase(gTrackDB);
00626 
00627   /* Close Serial Port */
00628   if (gPortID) {
00629     /* restore the default buffer before closing the serial port */
00630     DoSetReceiveBuffer(gPortID, NULL, 0);
00631     DoClose(gPortID);
00632   }
00633   
00634   /* Disable Serial Port Mux Control */
00635   sermux_enable(false);
00636   
00637   /* Set Application Preferences (unsaved) */
00638   PrefSetAppPreferences(kCreatorId, kPrefsId, kVersion, &gPrefs,
00639      sizeof(PrefsType), false);
00640   
00641   err = MathLibClose(MathLibRef, &usecount);
00642   ErrFatalDisplayIf(err, "Can't close MathLib");
00643   if (usecount == 0)
00644     SysLibRemove(MathLibRef);
00645   
00646 }
00647 
00648 
00649 /****************************************************************************/
00650 /**
00651  * \brief       PalmOS 2.x or higher specific operations
00652  *
00653  * \note        Copied from plucker-1.8
00654  *
00655  ****************************************************************************/
00656 static void OS2(void)
00657 {
00658 #if defined( HAVE_FIVEWAY_SDK ) || defined( HAVE_HANDSPRING_SDK )
00659     Err       err;
00660     UInt32    value;
00661 #endif
00662 #ifdef HAVE_FIVEWAY_SDK
00663     err = FtrGet( navFtrCreator, navFtrVersion, &value );
00664     if ( err == errNone )
00665         haveFiveWay = true;
00666 #endif
00667 #ifdef HAVE_HANDSPRING_SDK
00668     err = FtrGet( sysFileCSystem, sysFtrNumUIHardwareHas5Way, &value );
00669     if ( err == errNone ) {
00670         haveFiveWay = true;
00671         err = FtrGet( hsFtrCreator, hsFtrIDNavigationSupported, &value );
00672         if ( err == errNone ) {
00673             haveHsNav = true;
00674         }
00675     }
00676 #endif
00677 
00678 }
00679 
00680 
00681 /****************************************************************************/
00682 /**
00683  * \brief       Check if a FiveWay controller is present
00684  *
00685  * \note        Copied from plucker-1.8
00686  *
00687  * \returned    true if FiveWay controller is available, else false
00688  ****************************************************************************/
00689 static Boolean HaveFiveWay(void)
00690 {
00691 #if defined( HAVE_FIVEWAY_SDK ) || defined( HAVE_HANDSPRING_SDK )
00692     return haveFiveWay;
00693 #else
00694     return false;
00695 #endif
00696 }
00697 
00698 
00699 /*****************************************************************************
00700  * FUNCTION:    TimeUntilNextRead
00701  *
00702  * DESCRIPTION: Calculate time until next read from serial port is required.
00703  *
00704  ****************************************************************************/
00705 static 
00706 long TimeUntilNextRead(void)
00707 {
00708   if (!gFormOpened) {
00709     return evtWaitForever;
00710   } else {
00711     Int32 timeRemaining;
00712 
00713     timeRemaining = gNextReadTime - TimGetTicks();
00714 
00715     if (timeRemaining < 0)
00716       timeRemaining = 0;
00717     return timeRemaining;
00718   }
00719 }
00720 
00721 
00722 /*****************************************************************************
00723  * FUNCTION:    WarnUserIfHaventHeardFromGPSRecently
00724  *
00725  * DESCRIPTION: The name says it all. On the position form, all fields are
00726  *              cleared, on the Sky View form, the last data set is kept.
00727  *              The warning is shown on the StatusField of the current form.
00728  *
00729  ****************************************************************************/
00730 static 
00731 void WarnUserIfHaventHeardFromGPSRecently(void)
00732 {
00733   UInt16        form = FrmGetActiveFormID();
00734   
00735   if ((TimGetTicks() - gLastSuccessfulReception) > gTicksToLoseGPS) {
00736     UpdateStatus( STAT_NO_GPS );
00737     gGPSData.valid = false;
00738     
00739     switch (form) {
00740     
00741       case GPSMainForm:
00742         SetFieldText(TimeField, NULL, false, true);
00743         SetFieldText(LatitudeField, NULL, false, true);
00744         SetFieldText(LongitudeField, NULL, false, true);
00745         SetFieldText(SpeedField, NULL, false, true);
00746         SetFieldText(AltField, NULL, false, true);
00747         SetFieldText(CMGField, NULL, false, true);
00748         SetFieldText(MagField, NULL, false, true);
00749         break;
00750       
00751       case SkyviewForm:
00752         SetFieldText(TimeField, NULL, false, true);
00753         SetFieldText(PDOPField, NULL, false, true);
00754         SetFieldText(HDOPField, NULL, false, true);
00755         SetFieldText(VDOPField, NULL, false, true);
00756         SetFieldText(FixField, NULL, false, true);
00757         SetFieldText(SatsField, NULL, false, true);
00758         break;
00759       
00760       case NavigationForm:
00761         SetFieldText(TimeField, NULL, false, true);
00762         break;
00763     } // switch (form) 
00764   } // if ((TimGetTicks() - gLastSuccessfulReception) > gTicksToLoseGPS)
00765 }
00766 
00767 
00768 /*****************************************************************************
00769  * FUNCTION:    WaitForData
00770  *
00771  * DESCRIPTION: Wait for data available in serial buffer. Fill read buffer
00772  *              or wait for inter-character gap (0.5 s)
00773  *
00774  * PARAMETERS:  bufferSize      -- buffer size assigned to serial port
00775  *
00776  * RETURNED:    number of bytes available
00777  ****************************************************************************/
00778 static 
00779 UInt32 WaitForData(UInt32 bufferSize)
00780 {
00781   UInt32 numBytesPending = 0;
00782   Err   err;
00783   const Int32 kOneHalfSecond = gTicksPerSecond / 2;
00784 
00785   // We'll fill our read buffer, or 1/2 second between
00786   // bytes, whichever comes first.
00787   err = DoReceiveWait(gPortID, bufferSize, kOneHalfSecond);
00788   if (err == serErrLineErr) {
00789     DoReceiveFlush(gPortID, 1); // will clear the error
00790     return 0;                   
00791   } 
00792   if (err != serErrTimeOut)
00793     ErrFatalDisplayIf(err != 0, "DoReceiveWait");
00794   err = DoReceiveCheck(gPortID, &numBytesPending);
00795   if (err == serErrLineErr) {
00796     DoReceiveFlush(gPortID, 1); // will clear the error
00797     return 0;                   
00798   }
00799   ErrFatalDisplayIf(err != 0, "DoReceiveCheck Fail");
00800   
00801   return numBytesPending;
00802 }
00803 
00804 
00805 /*****************************************************************************
00806  * FUNCTION:    ReadAvailableData
00807  *
00808  * DESCRIPTION: Read data from serial buffer
00809  *
00810  * PARAMETERS:  data            -- pointer to string buffer
00811  *              bufferSize      -- buffer size assigned to serial port
00812  *              numBytesPending -- number of bytes available
00813  *
00814  * RETURNED:    always 0
00815  ****************************************************************************/
00816 static 
00817 Boolean ReadAvailableData(Char *data, UInt32 bufferSize, 
00818   UInt32 numBytesPending)
00819 {
00820    Err          err;
00821    UInt32       numBytes;
00822 
00823    // read however many bytes are waiting
00824    if (numBytesPending > bufferSize)
00825      numBytesPending = bufferSize;
00826    numBytes = DoReceive(gPortID, data, numBytesPending, 0, &err);
00827    if (err == serErrLineErr) {
00828      DoReceiveFlush(gPortID, 1);        // will clear the error
00829    } else
00830      data[numBytes] = '\0';             // null-terminate theData
00831    return 0;
00832 }
00833 
00834 
00835 
00836 
00837 /**********************************************************************/
00838 /**
00839  * \fn          Boolean ReadFromGPS(void)
00840  *
00841  * \brief       Reads data from GPS receiver.
00842  *
00843  *              If no messages are received for a certain time,
00844  *              a warning is generated.
00845  *              A large block of data is read from the serial buffer
00846  *              in one go. Then the data is parsed. Only complete
00847  *              messages (starting with $GP and ending with checksum) 
00848  *              and valid checksum are passed to the message handler
00849  *              function.
00850  *
00851  * \return      Flag which shows if message has been handled
00852  *              successfully. (TBD: all msgs, first msg, ???)
00853  *
00854  ***********************************************************************/
00855 Boolean ReadFromGPS(void)
00856 {
00857   Err           err;
00858   Boolean       updatedDisplay = false;
00859   Boolean       messageComplete = false;
00860   UInt32        numBytesPending;
00861   char          theData[(80+2)*5+1];    // three lines (80 chars with <CR><LF>
00862                                         //  + one for null byte
00863         
00864   // if we've gone too long without hearing from the GPS
00865   // tell the user
00866   WarnUserIfHaventHeardFromGPSRecently();
00867         
00868   numBytesPending = WaitForData(sizeof(theData)-1);
00869 
00870 #ifdef DEBUG_FORM
00871   if (numBytesPending < gMinReceived) {
00872     gMinReceived = numBytesPending;
00873   }
00874   if (numBytesPending > gMaxReceived) {
00875     gMaxReceived = numBytesPending;
00876   }
00877 #endif  
00878   
00879   if (numBytesPending > 0) {
00880     char                *startOfMessage;        /* ptr to start of message */
00881     char                *endOfMessage;          /* ptr to end   of message */
00882     unsigned char       chk;                    /* checksum */
00883 
00884     Char                exp[3];                 /* expected checksum (string) */
00885     Char                act[3];                 /* actual checksum   (string) */
00886 
00887     err = ReadAvailableData(theData, sizeof(theData) - 1, numBytesPending);
00888     if (err)
00889       return false;
00890 
00891     /* start parsing at start of buffer */
00892     startOfMessage = theData;
00893            
00894     /* loop while start of message can be found */
00895     while ((startOfMessage = StrStr(startOfMessage, "$GP")) != NULL) {
00896       
00897       /* start at start of message, skip '$' for checksum calculation */
00898       endOfMessage = startOfMessage + 1;
00899       messageComplete = false;
00900       chk = 0;
00901       
00902       /* loop until end of buffer (or end of message detected) */
00903       while (*endOfMessage != '\0') {
00904         
00905         if (*endOfMessage == '*') {
00906           /* checksum delimiter found */
00907           
00908           if (( *(endOfMessage+1) != '\0') &&
00909               ( *(endOfMessage+2) != '\0')) {
00910             /* checksum found */
00911             
00912             /* expected checksum */
00913             exp[0] = *(endOfMessage+1);
00914             exp[1] = *(endOfMessage+2);
00915             
00916             /* actual checksum */
00917             act[0] = nibble2hex((chk & 0xF0) >> 4);
00918             act[1] = nibble2hex( chk & 0x0F);
00919             
00920             if ((exp[0] == act[0]) && (exp[1] == act[1])) {
00921               /* checksum ok, handle message */
00922               updatedDisplay = HandleMessage(startOfMessage);
00923             }
00924             
00925 #ifdef DEBUG_FORM
00926             else
00927             {
00928               /* increment checksum error counter */
00929               if (gChkErrs != 0xFFFFFFFF) {
00930                 gChkErrs++;
00931               }
00932             }
00933 #endif
00934             
00935             // end of message found 
00936             messageComplete = true;
00937             
00938           } /* checksum received */
00939           
00940           // search for start of next message
00941           //   after current message
00942           startOfMessage = endOfMessage;
00943           
00944           break;
00945         } /* if (*endOfMessage == '*') */
00946         
00947         /* update checksum */
00948         chk ^= *endOfMessage;
00949         
00950         /* next character */
00951         endOfMessage++;
00952       } /* while (*endOfMessage != '\0') */
00953       
00954       // end of buffer contents
00955       if (!messageComplete)
00956         break;
00957     }
00958   }
00959   return updatedDisplay;
00960 }
00961 
00962 
00963 /*****************************************************************************
00964  * FUNCTION:    ApplicationHandleEvent
00965  *
00966  * DESCRIPTION: Set Application Event Handler to Form specific Handler.
00967  *
00968  * PARAMETERS:  event   -- pointer to event (only frmLoadEvent handled)
00969  *
00970  * RETURNED:    Event handled as boolean.
00971  ****************************************************************************/
00972 static Boolean ApplicationHandleEvent(EventPtr event)
00973 {
00974   FormPtr       form;
00975   UInt16        formId;
00976   Boolean       handled = false;
00977 
00978   if (event->eType == frmLoadEvent) {
00979     /* Load the form resource specified in the event then activate the form. */
00980     formId = event->data.frmLoad.formID;
00981     form = FrmInitForm(formId);
00982     FrmSetActiveForm(form);
00983 
00984     switch (formId) {
00985       case GPSMainForm:
00986               FrmSetEventHandler(form, MainFormHandleEvent);
00987               break;
00988 
00989       case SkyviewForm:
00990               FrmSetEventHandler(form, SkyviewFormHandleEvent);
00991               break;
00992 
00993       case NavigationForm:
00994               FrmSetEventHandler(form, NavigationFormHandleEvent);
00995               break;
00996 
00997       case MapForm:
00998               FrmSetEventHandler(form, MapFormHandleEvent);
00999               break;
01000 
01001       case GPSPortForm:
01002               FrmSetEventHandler(form, PortFormHandleEvent);
01003               break;
01004 
01005       case FileSelForm:
01006               FrmSetEventHandler(form, FileSelFormHandleEvent);
01007               break;
01008 
01009       case MiscOptsForm:
01010               FrmSetEventHandler(form, MiscOptsFormHandleEvent);
01011               break;
01012 
01013       case MapOptsForm:
01014               FrmSetEventHandler(form, MapOptsFormHandleEvent);
01015               break;
01016 
01017       case WaypointForm:
01018               FrmSetEventHandler(form, WaypointFormHandleEvent);
01019               break;
01020 
01021       case WayptEditForm:
01022               FrmSetEventHandler(form, WayptEditFormHandleEvent);
01023               break;
01024 
01025       case RouteForm:
01026               FrmSetEventHandler(form, RouteFormHandleEvent);
01027               break;
01028 
01029       case RouteEditForm:
01030               FrmSetEventHandler(form, RouteEditFormHandleEvent);
01031               break;
01032 
01033       case TrackForm:
01034               FrmSetEventHandler(form, TrackFormHandleEvent);
01035               break;
01036 
01037       case AboutForm:
01038               FrmSetEventHandler(form, AboutFormHandleEvent);
01039               break;
01040        
01041       case ApproachForm:
01042               FrmSetEventHandler(form, ApproachFormHandleEvent);
01043               break;
01044      
01045 #ifdef DEBUG_FORM
01046       case DebugForm:
01047               FrmSetEventHandler(form, DebugFormHandleEvent);
01048               break;
01049 #endif          
01050     }
01051     handled = true;
01052   }
01053 
01054   return handled;
01055 }
01056 
01057 
01058 /*****************************************************************************
01059  * FUNCTION:    EventLoop
01060  *
01061  * DESCRIPTION: Main Event Loop
01062  *
01063  ****************************************************************************/
01064 static 
01065 void EventLoop(void)
01066 {
01067         EventType       event;
01068         UInt16          error;
01069         
01070         do {
01071                 /* Wait for OS Event or time-out (to read from serial port) */
01072                 EvtGetEvent(&event, TimeUntilNextRead());
01073                 
01074                 /* Reset Auto Power-Off Timer if Auto Power-Off is disabled */
01075                 if (! gPrefs.pwroff) {
01076                   EvtResetAutoOffTimer();
01077                 }
01078 
01079 #ifdef USE_HARD_KEYS
01080                 /* use the hard keys to switch between main forms */
01081                 if ((event.eType == keyDownEvent) && 
01082                     (event.data.keyDown.modifiers & commandKeyMask)) {
01083                   
01084                   switch (event.data.keyDown.chr) {
01085                     case vchrHard1:
01086                       event.eType = menuEvent;
01087                       event.data.menu.itemID = PositionMenu;
01088                       EvtAddEventToQueue(&event);
01089                       break;
01090                       
01091                     case vchrHard2:
01092                       event.eType = menuEvent;
01093                       event.data.menu.itemID = SkyviewMenu;
01094                       EvtAddEventToQueue(&event);
01095                       break;
01096                     
01097                     case vchrHard3:
01098                       event.eType = menuEvent;
01099                       event.data.menu.itemID = NavigationMenu;
01100                       EvtAddEventToQueue(&event);
01101                       break;
01102                     
01103                     case vchrHard4:
01104                       event.eType = menuEvent;
01105                       event.data.menu.itemID = MapMenu;
01106                       EvtAddEventToQueue(&event);
01107                       break; 
01108                   }
01109                 }               
01110 #endif
01111 
01112                 /* Dispatch Event */
01113                 if (! SysHandleEvent(&event))
01114                   if (! MenuHandleEvent(0, &event, &error))
01115                     if (! ApplicationHandleEvent(&event))
01116                       FrmDispatchEvent(&event);
01117                         
01118         } while (event.eType != appStopEvent);
01119 }
01120 
01121 
01122 /****************************************************************************/
01123 /**
01124  * \fn          UInt32 PilotMain(UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags)
01125  *
01126  * \brief       Application Entry Function
01127  *
01128  * \param       cmd             Launch Code
01129  * \param       cmdPBP          Command Parameter Block Pointer
01130  * \param       launchFlags     Launch Flags (set by OS)
01131  *
01132  * \return      always 0
01133  *
01134  ****************************************************************************/
01135 UInt32 PilotMain(UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags)
01136 {
01137   UInt16 error;         
01138 
01139   error = RomVersionCompatible (kMinimumVersion, launchFlags);
01140   if (error)
01141           return error;
01142 
01143   if (cmd == sysAppLaunchCmdNormalLaunch) {
01144     if (!AppStart()) {
01145       EventLoop();
01146       AppStop();
01147     }
01148   }
01149   
01150   return 0;
01151 }

Created: Mon, 08 Oct 2007 22:33:16 +0200
Copyright ©2004 M. Prinke