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 }