00001 /***************************************************************************** 00002 * 00003 * $RCSfile: NavigationForm_8c-source.html,v $ 00004 * 00005 * GPS4Palm Navigation Form 00006 * 00007 * This program is Copyright (C) 03/2003 Matthias Prinke 00008 * <matthias.prinke@surfeu.de> and covered by GNU's GPL. 00009 * In particular, this program is free software and comes WITHOUT 00010 * ANY WARRANTY. 00011 * 00012 * $Author: mp $ 00013 * 00014 * $Date: 2007-10-08 20:40:34 $ 00015 * 00016 * $Revision: 1.7.2.1 $ 00017 * 00018 * $Log: NavigationForm_8c-source.html,v $ 00018 * Revision 1.7.2.1 2007-10-08 20:40:34 mp 00018 * updated for gps4palm V0.9.5 beta 00018 * 00019 * Revision 1.26 2005-05-06 13:38:34 mp 00020 * removed assignment to gHdFtrSet 00021 * 00022 * Revision 1.25 2005/04/24 14:06:43 mp 00023 * added High-Density Display support 00024 * 00025 * Revision 1.24 2005/04/02 10:09:43 mp 00026 * modified Position2Clipboard() and Position2Geodb() to return 'handled' 00027 * 00028 * Revision 1.23 2005/04/02 07:26:59 mp 00029 * added PosgeodbMenu event handling 00030 * 00031 * Revision 1.22 2005/03/25 13:45:11 mp 00032 * added PosclipMenu event handling 00033 * 00034 * Revision 1.21 2005/01/23 18:40:10 mp 00035 * added PortsMenu event handling 00036 * 00037 * Revision 1.20 2004/12/10 20:03:04 mp 00038 * added waypoint selection with up/down keys, 00039 * replaced DmGet1Resource by DmGetResource 00040 * 00041 * Revision 1.19 2004/12/09 17:33:37 mp 00042 * replaced strings by string resources 00043 * 00044 * Revision 1.18 2004/12/08 20:49:22 mp 00045 * added track logging 00046 * 00047 * Revision 1.17 2004/11/30 20:44:06 mp 00048 * added TrackMenu event handling 00049 * 00050 * Revision 1.16 2004/11/27 10:20:31 mp 00051 * replaced error handling code by calling Die() 00052 * 00053 * Revision 1.15 2004/11/26 20:09:40 mp 00054 * added error handling for WinCreateOffscreenWindow(), fixed comments 00055 * 00056 * Revision 1.14 2004/11/25 20:06:20 mp 00057 * added NotifyApproach() 00058 * 00059 * Revision 1.13 2004/11/24 21:15:20 mp 00060 * moved static function declarations from header to implementation file 00061 * 00062 * Revision 1.12 2004/11/23 17:48:33 mp 00063 * removed unused variables 00064 * 00065 * Revision 1.11 2004/11/20 15:51:25 mp 00066 * added display_wpt(), NavigationPrevWptButton/NavigationNextWptButton 00067 * handling, and automatic route waypoint selection 00068 * 00069 * Revision 1.10 2004/11/11 21:36:25 mp 00070 * implemented active Route Information 00071 * 00072 * Revision 1.9 2004/04/29 19:02:05 mp 00073 * added RouteForm, modified for doxygen 00074 * 00075 * Revision 1.8 2004/03/16 20:00:42 mp 00076 * Fixed waypoint ID display. Added deletion of window handle upon 00077 * frmCloseEvent. Modified bearing pointer. 00078 * 00079 * Revision 1.7 2004/03/13 14:59:28 mp 00080 * added/modified data display 00081 * 00082 * Revision 1.6 2004/03/11 21:40:06 mp 00083 * added data display and DTK pointer 00084 * 00085 * Revision 1.5 2004/02/28 17:21:43 mp 00086 * added menuEvent WaypointMenu 00087 * 00088 * Revision 1.4 2003/11/20 20:45:01 mp 00089 * added status redraw on frmOpenEvent 00090 * 00091 * Revision 1.3 2003/11/18 20:55:40 mp 00092 * added MiscOptsMenu, added current Form to Application Preferences 00093 * 00094 * Revision 1.2 2003/10/20 17:25:50 mp 00095 * added field deallocation on frmCloseEvent 00096 * 00097 * Revision 1.1.1.1 2003/07/14 18:59:29 mp 00098 * Imported GPS4Palm to CVS revision control. 00099 * 00100 * 00101 ****************************************************************************/ 00102 #include <PalmOS.h> 00103 #include <PalmCompatibility.h> 00104 #include "MathLib.h" 00105 #include "ResourceDefines.h" 00106 #include "Serial.h" 00107 #include "Sinetab.h" 00108 #include "NavigationForm.h" 00109 #include "GPS.h" 00110 #include "HandleMessage.h" 00111 #include "Utils.h" 00112 #include "Data.h" 00113 #include "fp.h" 00114 #include "geo.h" 00115 #include "Clip.h" 00116 #include "common.h" 00117 00118 /* Global Variables */ 00119 00120 /** Navigation window handle for save-behind (Compass). */ 00121 WinHandle gNavigationH; 00122 00123 extern PrefsType gPrefs; /* Preferences data structure */ 00124 extern DmOpenRef gWaypointDB; /* Data Base reference */ 00125 extern GPSType gGPSData; /* GPS Data */ 00126 extern Boolean gHdFtrSet; /* High-Density Display */ 00127 00128 /** Constants for distance unit conversions and display */ 00129 extern const struct { 00130 char *unit; 00131 double conv; 00132 } dst_c[]; 00133 00134 /** Constants for speed unit conversions and display */ 00135 extern const struct { 00136 char *unit; 00137 double conv; 00138 } spd_c[]; 00139 00140 #ifndef WinDrawPixel 00141 #define WinDrawPixel(x,y) WinDrawLine((x),(y),(x),(y)) 00142 #endif 00143 00144 /* Static Functions */ 00145 static void display_sog(void) NAV_SECTION; 00146 static void display_cmg(void) NAV_SECTION; 00147 static void display_dst(double dist) NAV_SECTION; 00148 static void display_trn(double turn) NAV_SECTION; 00149 static void display_vmg(double vmg) NAV_SECTION; 00150 static void display_wpt(double *lat, double *lon) NAV_SECTION; 00151 static void hours_to_hms(double hours, UInt16 *hh, UInt16 *mm, 00152 UInt16 *ss) NAV_SECTION; 00153 static void NavigationFormInit(void) NAV_SECTION; 00154 static void DrawNavigation(void) NAV_SECTION; 00155 00156 00157 /***************************************************************************** 00158 * FUNCTION: WayptEditFormInit 00159 * 00160 * DESCRIPTION: Navigation Form Init Function 00161 * 00162 * GLOBALS: gFormOpened -- indicates if a form (using GPS data) 00163 * has been opened 00164 ****************************************************************************/ 00165 static 00166 void NavigationFormInit(void) 00167 { 00168 gFormOpened = true; 00169 } 00170 00171 00172 /***************************************************************************** 00173 * FUNCTION: hours_to_hms 00174 * 00175 * DESCRIPTION: Convert fractional hours to integer hours, minutes and seconds 00176 * 00177 * PARAMETERS: hours -- decimal hours 00178 * hh -- integer hours (returned by ref) 00179 * mm -- integer minutes (returned by ref) 00180 * ss -- integer seconds (returned by ref) 00181 * 00182 * RETURNED: % 00183 ****************************************************************************/ 00184 static 00185 void hours_to_hms(double hours, UInt16 *hh, UInt16 *mm, UInt16 *ss) 00186 { 00187 double sec; /* seconds */ 00188 double frac; /* fractional part */ 00189 double ipart; /* integer part */ 00190 00191 /* hours */ 00192 frac = modf(hours, &ipart) * 60.0; 00193 *hh = (UInt16)ipart; 00194 00195 /* minutes */ 00196 sec = modf(frac, &ipart) * 60.0; 00197 *mm = (UInt16)ipart; 00198 00199 /* seconds */ 00200 *ss = (UInt16)sec; 00201 } 00202 00203 00204 /***************************************************************************** 00205 * FUNCTION: DrawNavigation 00206 * 00207 * DESCRIPTION: Draw Navigation Form ("Compass") and save it to off-screen 00208 * window. 00209 * 00210 * GLOBALS: gNavigationH -- Off-screen window handle 00211 * 00212 * PARAMETERS: - 00213 * 00214 * RETURNED: - 00215 ****************************************************************************/ 00216 static 00217 void DrawNavigation(void) 00218 { 00219 UInt16 x; /* x-coordinate */ 00220 UInt16 y; /* y-coordinate */ 00221 PointType p1; /* point 1 */ 00222 PointType p2; /* point 2 */ 00223 UInt16 r; /* radius */ 00224 UInt16 phi; /* angle */ 00225 UInt16 err; /* error code */ 00226 RectangleType rect; /* rectangle structure */ 00227 00228 if (gHdFtrSet) { 00229 WinPushDrawState(); 00230 WinSetCoordinateSystem(kCoordinatesNative); 00231 } 00232 00233 /* Outer circle */ 00234 r = (gHdFtrSet) ? WinScaleCoord(NAV_R2, false) : NAV_R2; 00235 p1.x = (gHdFtrSet) ? WinScaleCoord(NAV_X, false) : NAV_X; 00236 p1.y = (gHdFtrSet) ? WinScaleCoord(NAV_Y, false) : NAV_Y; 00237 for (phi=0; phi<360; phi++) { 00238 /* Sinus/Cosinus functions using table lookup */ 00239 x = p1.x + r * icos(phi) / 32768; 00240 y = p1.y - r * isin(phi) / 32768; 00241 00242 /* 00243 * Note: 00244 * For High-Density, a step size of one degree does not provide 00245 * enough points for a continuous circle. Connecting the points 00246 * with a line seems to work good enough. (and is still fast) 00247 */ 00248 if (phi == 0) { 00249 WinDrawPixel(x, y); 00250 } else { 00251 WinDrawLine(x, y, p2.x, p2.y); 00252 } 00253 p2.x = x; 00254 p2.y = y; 00255 } 00256 00257 /* Inner circle */ 00258 r = (gHdFtrSet) ? WinScaleCoord(NAV_R1, false) : NAV_R1; 00259 for (phi=0; phi<360; phi++) { 00260 /* Sinus/Cosinus functions using table lookup */ 00261 x = p1.x + r * icos(phi) / 32768; 00262 y = p1.y - r * isin(phi) / 32768; 00263 00264 WinDrawPixel(x, y); 00265 } 00266 00267 /* Center */ 00268 p1.x = NAV_X-2; 00269 p1.y = NAV_Y; 00270 p2.x = NAV_X+2; 00271 p2.y = NAV_Y; 00272 if (gHdFtrSet) { 00273 WinScalePoint(&p1, false); 00274 WinScalePoint(&p2, false); 00275 } 00276 WinDrawLine(p1.x, p1.y, p2.x, p2.y); 00277 00278 p1.x = NAV_X; 00279 p1.y = NAV_Y-2; 00280 p2.x = NAV_X; 00281 p2.y = NAV_Y+2; 00282 if (gHdFtrSet) { 00283 WinScalePoint(&p1, false); 00284 WinScalePoint(&p2, false); 00285 } 00286 WinDrawLine(p1.x, p1.y, p2.x, p2.y); 00287 00288 p1.x = 2 * NAV_R2; 00289 p1.y = 2 * NAV_R2; 00290 if (gHdFtrSet) WinScalePoint(&p1, false); 00291 gNavigationH = WinCreateOffscreenWindow(p1.x, p1.y, nativeFormat, &err); 00292 00293 if (!gNavigationH) { 00294 /* error handling */ 00295 if (gHdFtrSet) { 00296 WinPopDrawState(); 00297 } 00298 Die("Cannot create OffscreenWindow in NavigationForm!"); 00299 return; 00300 } 00301 00302 p1.x = NAV_X-NAV_R2; 00303 p1.y = NAV_Y-NAV_R2; 00304 if (gHdFtrSet) WinScalePoint(&p1, false); 00305 x = (gHdFtrSet) ? WinScaleCoord(2 * NAV_R2, false) : 2 * NAV_R2; 00306 y = (gHdFtrSet) ? WinScaleCoord(2 * NAV_R2, false) : 2 * NAV_R2; 00307 RctSetRectangle(&rect, p1.x, p1.y, x /* w */, y /* h */); 00308 00309 WinCopyRectangle( NULL, /* WinHandle srcWin, draw window */ 00310 gNavigationH, /* WinHandle dstWin, draw window */ 00311 &rect, /* RectangleType *srcRect */ 00312 0, /* Coord destX */ 00313 0, /* Coord destY */ 00314 winPaint /* WinDrawOperation mode */); 00315 00316 if (gHdFtrSet) { 00317 WinPopDrawState(); 00318 } 00319 } 00320 00321 00322 /***************************************************************************** 00323 * FUNCTION: display_sog 00324 * 00325 * DESCRIPTION: Displays Speed Over Ground 00326 * 00327 * GLOBALS: gPrefs -- application preferences 00328 * gGPSData -- GPS data 00329 * 00330 * PARAMETERS: % 00331 * 00332 * RETURNED: % 00333 ****************************************************************************/ 00334 static 00335 void display_sog(void) 00336 { 00337 double tmp; 00338 Char sog_str[12]; 00339 00340 /* convert to preferred unit */ 00341 tmp = gGPSData.sog * spd_c[gPrefs.units.spd_unit].conv; 00342 00343 /* convert to string, adapt number of decimals to value */ 00344 if (tmp < 100.0) { 00345 format_number(tmp, 2, sog_str); 00346 } else if (tmp < 1000.0) { 00347 format_number(tmp, 1, sog_str); 00348 } else { 00349 format_number(tmp, 0, sog_str); 00350 } 00351 00352 /* append unit to string */ 00353 StrCat(sog_str, " "); 00354 StrCat(sog_str, spd_c[gPrefs.units.spd_unit].unit); 00355 00356 /* display string */ 00357 SetFieldText(NavigationSogField, sog_str, false, true); 00358 } 00359 00360 00361 /***************************************************************************** 00362 * FUNCTION: display_cmg 00363 * 00364 * DESCRIPTION: Displays Course Made Good (= Course Over Ground) 00365 * 00366 * GLOBALS: gGPSData -- GPS data 00367 * 00368 * PARAMETERS: % 00369 * 00370 * RETURNED: % 00371 ****************************************************************************/ 00372 static 00373 void display_cmg(void) 00374 { 00375 Char cmg_str[12]; 00376 00377 /* convert to string */ 00378 format_number(gGPSData.cmg, 1, cmg_str); 00379 00380 /* append unit to string */ 00381 StrCat(cmg_str, "°"); 00382 00383 /* display string */ 00384 SetFieldText(NavigationCmgField, cmg_str, false, true); 00385 } 00386 00387 00388 /***************************************************************************** 00389 * FUNCTION: display_dst 00390 * 00391 * DESCRIPTION: Displays Distance To Waypoint 00392 * 00393 * GLOBALS: gPrefs -- application preferences 00394 * 00395 * PARAMETERS: dist -- distance in km 00396 * 00397 * RETURNED: % 00398 ****************************************************************************/ 00399 static 00400 void display_dst(double dist) 00401 { 00402 Char dist_str[8]; 00403 00404 /* convert to preferred unit */ 00405 dist *= dst_c[gPrefs.units.dst_unit].conv; 00406 00407 /* adapt number of decimals to value */ 00408 if (dist < 2.0) { 00409 format_number(dist, 3, dist_str); 00410 } else if (dist < 10.0) { 00411 format_number(dist, 2, dist_str); 00412 } else if (dist < 100.0) { 00413 format_number(dist, 1, dist_str); 00414 } else { 00415 format_number(dist, 0, dist_str); 00416 } 00417 00418 /* append unit to string */ 00419 StrCat(dist_str, " "); 00420 StrCat(dist_str, dst_c[gPrefs.units.dst_unit].unit); 00421 00422 /* display DST string */ 00423 SetFieldText(NavigationDstField, dist_str, false, true); 00424 } 00425 00426 00427 /***************************************************************************** 00428 * FUNCTION: display_trn 00429 * 00430 * DESCRIPTION: Displays Turn Angle 00431 * 00432 * PARAMETERS: turn -- turn in degrees, (pos: right/neg: left) 00433 * 00434 * RETURNED: % 00435 ****************************************************************************/ 00436 static 00437 void display_trn(double turn) 00438 { 00439 Char trn_str[8]; 00440 00441 if (turn < 0.0) { 00442 format_number(-turn, 1, trn_str); 00443 StrCat(trn_str, "°L"); 00444 } else { 00445 format_number(turn, 1, trn_str); 00446 StrCat(trn_str, "°R"); 00447 } 00448 SetFieldText(NavigationTrnField, trn_str, false, true); 00449 } 00450 00451 00452 /***************************************************************************** 00453 * FUNCTION: display_vmg 00454 * 00455 * DESCRIPTION: Displays Velocity Made Good 00456 * 00457 * GLOBALS: gPrefs -- application preferences 00458 * 00459 * PARAMETERS: vmg -- velocity made good (in kts) 00460 * 00461 * RETURNED: % 00462 ****************************************************************************/ 00463 static 00464 void display_vmg(double vmg) 00465 { 00466 Char vmg_str[10]; 00467 double tmp; 00468 00469 /* convert to preferred unit */ 00470 tmp = vmg * spd_c[gPrefs.units.spd_unit].conv; 00471 00472 /* convert to string, adapt number of decimals to value */ 00473 if (tmp < 100.0) { 00474 format_number(tmp, 2, vmg_str); 00475 } else if (tmp < 1000.0) { 00476 format_number(tmp, 1, vmg_str); 00477 } else { 00478 format_number(tmp, 0, vmg_str); 00479 } 00480 00481 /* append unit to string */ 00482 StrCat(vmg_str, " "); 00483 StrCat(vmg_str, spd_c[gPrefs.units.spd_unit].unit); 00484 00485 /* display string */ 00486 SetFieldText(NavigationVmgField, vmg_str, false, true); 00487 } 00488 00489 00490 /****************************************************************************/ 00491 /** 00492 * \brief Display waypoint ID and update waypoint position 00493 * 00494 * \param lat latitude returned by reference 00495 * \param lon longitude returned by reference 00496 * 00497 ****************************************************************************/ 00498 static 00499 void display_wpt(double *lat, double *lon) 00500 { 00501 packed_waypoint_t *packed_waypoint; /* packed waypoint ptr */ 00502 waypoint_t waypoint; /* unpacked waypoint */ 00503 MemHandle waypointDBEntry; /* waypoint record handle */ 00504 UInt16 rec; /* record index */ 00505 Err err; /* error code */ 00506 Char tmp[7]; /* waypoint identifier */ 00507 MemHandle strH; /* string handle */ 00508 MemPtr strP; /* string ptr */ 00509 00510 /* default "Waypoint Identifier" */ 00511 /* get string from resource */ 00512 strH = DmGetResource(strRsc, NoWptStr); 00513 00514 if (strH != NULL) { 00515 /* string handle valid, lock it */ 00516 strP = MemHandleLock(strH); 00517 00518 /* copy string */ 00519 StrCopy(tmp, strP); 00520 00521 /* unlock string handle */ 00522 MemHandleUnlock(strH); 00523 00524 /* release string resource */ 00525 DmReleaseResource(strH); 00526 } 00527 00528 /* display active waypoint */ 00529 err = DmFindRecordByID(gWaypointDB, gPrefs.act_wpt.waypointID, 00530 &rec); 00531 00532 if (!err) { 00533 /* active waypoint found */ 00534 waypointDBEntry = DmQueryRecord(gWaypointDB, rec); 00535 packed_waypoint = 00536 (packed_waypoint_t *)MemHandleLock(waypointDBEntry); 00537 UnpackWaypoint(&waypoint, packed_waypoint); 00538 MemSet((Char *)tmp, 7, 0); 00539 StrNCopy(tmp, (Char *)&waypoint.ident, 6); 00540 *lat = semi2deg(waypoint.posn.lat); 00541 *lon = semi2deg(waypoint.posn.lon); 00542 MemHandleUnlock(waypointDBEntry); 00543 } 00544 00545 CtlSetLabel((ControlPtr)GetObjectFromActiveForm(NavigationWptIDSel), tmp); 00546 } 00547 00548 00549 /****************************************************************************/ 00550 /** 00551 * \brief Navigation Form event handler 00552 * 00553 * \param eventP pointer to event structure 00554 * 00555 * \return Status flag: event handled 00556 ****************************************************************************/ 00557 Boolean NavigationFormHandleEvent(EventPtr eventP) 00558 { 00559 Boolean handled; /* flag: event handled */ 00560 Boolean updatedDisplay; /* flag: updated display */ 00561 Err err; /* error code */ 00562 UInt16 rec; /* record index */ 00563 packed_waypoint_t *packed_waypoint; /* packed waypoint ptr */ 00564 waypoint_t waypoint; /* unpacked waypoint */ 00565 MemHandle waypointDBEntry; /* waypoint record handle */ 00566 route_t *route; /* route */ 00567 MemHandle routeDBEntry; /* route record handle */ 00568 static Char tmp[10]; /* temp. string buffer */ 00569 static double wpt_lat; /* lat of waypoint */ 00570 static double wpt_lon; /* lon of waypoint */ 00571 double dist; /* distance to waypoint */ 00572 double brg; /* bearing */ 00573 double turn; /* turn */ 00574 double vmg; /* velocity made good */ 00575 double ttg; /* time to go in dec. hours */ 00576 Int32 trk; /* track as integer */ 00577 static Int32 otrk; /* old track */ 00578 Int32 x, y; /* screen coordinates */ 00579 Int32 r; /* radius for track pointer */ 00580 PointType p1; /* point for track pointer */ 00581 MemHandle strH; /* string handle */ 00582 MemPtr strP; /* string ptr */ 00583 00584 handled = false; 00585 00586 switch (eventP->eType) 00587 { 00588 case frmOpenEvent: 00589 gPrefs.form = NavigationForm; 00590 00591 NavigationFormInit(); 00592 FrmDrawForm(FrmGetActiveForm()); 00593 DrawNavigation(); 00594 UpdateStatus(STAT_REDRAW); 00595 00596 if (gPrefs.act_rte.valid || gPrefs.act_wpt.valid) { 00597 /* display waypoint and get position */ 00598 display_wpt(&wpt_lat, &wpt_lon); 00599 } 00600 00601 /* default "Route Identifier" */ 00602 /* get string from resource */ 00603 strH = DmGetResource(strRsc, NoRteStr); 00604 00605 if (strH != NULL) { 00606 /* string handle valid, lock it */ 00607 strP = MemHandleLock(strH); 00608 00609 /* copy string */ 00610 StrCopy(tmp, strP); 00611 00612 /* unlock string handle */ 00613 MemHandleUnlock(strH); 00614 00615 /* release string resource */ 00616 DmReleaseResource(strH); 00617 } 00618 00619 if (gPrefs.act_rte.valid) { 00620 /* display active route */ 00621 err = DmFindRecordByID(gRouteDB, gPrefs.act_rte.routeID, 00622 &rec); 00623 00624 if (!err) { 00625 /* active route found */ 00626 routeDBEntry = DmQueryRecord(gRouteDB, rec); 00627 route = (route_t *)MemHandleLock(routeDBEntry); 00628 MemSet((Char *)tmp, 9, 0); 00629 00630 /* get string from resource */ 00631 strH = DmGetResource(strRsc, RteNoStr); 00632 00633 if (strH != NULL) { 00634 /* string handle valid, lock it */ 00635 strP = MemHandleLock(strH); 00636 00637 StrPrintF(tmp, "%s%-3d", strP, route->nmbr); 00638 00639 /* unlock string handle */ 00640 MemHandleUnlock(strH); 00641 00642 /* release string resource */ 00643 DmReleaseResource(strH); 00644 } 00645 MemHandleUnlock(routeDBEntry); 00646 } 00647 } 00648 CtlSetLabel((ControlPtr)GetObjectFromActiveForm(NavigationRteIDSel), tmp); 00649 00650 handled = true; 00651 break; 00652 00653 case menuEvent: 00654 switch (eventP->data.menu.itemID) { 00655 00656 case PositionMenu: 00657 FrmGotoForm(GPSMainForm); 00658 handled = true; 00659 break; 00660 00661 case SkyviewMenu: 00662 FrmGotoForm(SkyviewForm); 00663 handled = true; 00664 break; 00665 00666 case MapMenu: 00667 FrmGotoForm(MapForm); 00668 handled = true; 00669 break; 00670 00671 case MiscOptsMenu: 00672 FrmGotoForm(MiscOptsForm); 00673 handled = true; 00674 break; 00675 00676 case MapOptsMenu: 00677 FrmGotoForm(MapOptsForm); 00678 handled = true; 00679 break; 00680 00681 case PortsMenu: 00682 if (gNewSerialManager) { 00683 FrmGotoForm(GPSPortForm); 00684 } 00685 handled = true; 00686 break; 00687 00688 case WaypointMenu: 00689 FrmGotoForm(WaypointForm); 00690 handled = true; 00691 break; 00692 00693 case RouteMenu: 00694 FrmGotoForm(RouteForm); 00695 handled = true; 00696 break; 00697 00698 case TrackMenu: 00699 FrmGotoForm(TrackForm); 00700 handled = true; 00701 break; 00702 00703 case PosclipMenu: 00704 handled = Position2Clipboard(gGPSData, gPrefs.units); 00705 break; 00706 00707 case PosgeodbMenu: 00708 handled = Position2Geodb(gGPSData); 00709 break; 00710 00711 case AboutMenu: 00712 FrmGotoForm(AboutForm); 00713 handled = true; 00714 break; 00715 00716 #ifdef DEBUG_FORM 00717 case DebugMenu: 00718 FrmGotoForm(DebugForm); 00719 handled = true; 00720 break; 00721 #endif 00722 } 00723 break; 00724 00725 case ctlSelectEvent: 00726 case keyDownEvent: 00727 00728 /* Previous Waypoint */ 00729 if ((eventP->eType == ctlSelectEvent && 00730 eventP->data.ctlSelect.controlID == NavigationPrevWptButton) || 00731 (eventP->eType == keyDownEvent && 00732 eventP->data.keyDown.chr == pageUpChr)) { 00733 00734 if (gPrefs.act_rte.valid) { 00735 if (gPrefs.act_rte.wpt_index == 0) 00736 break; 00737 00738 /* select previous waypoint */ 00739 gPrefs.act_rte.wpt_index--; 00740 00741 /* get active route */ 00742 err = DmFindRecordByID(gRouteDB, gPrefs.act_rte.routeID, 00743 &rec); 00744 00745 if (!err) { 00746 /* active route found */ 00747 routeDBEntry = DmQueryRecord(gRouteDB, rec); 00748 00749 /* lock record */ 00750 route = (route_t *)MemHandleLock(routeDBEntry); 00751 00752 /* update active waypoint record ID */ 00753 gPrefs.act_wpt.waypointID = 00754 route->wpt_rec_id[gPrefs.act_rte.wpt_index]; 00755 00756 /* unlock route record */ 00757 MemHandleUnlock(routeDBEntry); 00758 00759 /* display new active waypoint */ 00760 display_wpt(&wpt_lat, &wpt_lon); 00761 00762 } else { 00763 gPrefs.act_wpt.valid = false; 00764 } /* if (!err) */ 00765 } /* if (gPrefs.act_rte.valid) */ 00766 } 00767 00768 /* Next Waypoint */ 00769 if ((eventP->eType == ctlSelectEvent && 00770 eventP->data.ctlSelect.controlID == NavigationNextWptButton) || 00771 (eventP->eType == keyDownEvent && 00772 eventP->data.keyDown.chr == pageDownChr)) { 00773 00774 if (gPrefs.act_rte.valid) { 00775 00776 /* get active route */ 00777 err = DmFindRecordByID(gRouteDB, gPrefs.act_rte.routeID, 00778 &rec); 00779 00780 if (!err) { 00781 /* active route found */ 00782 routeDBEntry = DmQueryRecord(gRouteDB, rec); 00783 00784 /* lock record */ 00785 route = (route_t *)MemHandleLock(routeDBEntry); 00786 00787 if (gPrefs.act_rte.wpt_index == route->items-1) { 00788 /* last waypoint already active */ 00789 MemHandleUnlock(routeDBEntry); 00790 break; 00791 } 00792 00793 /* select next waypoint */ 00794 gPrefs.act_rte.wpt_index++; 00795 00796 /* update active waypoint record ID */ 00797 gPrefs.act_wpt.waypointID = 00798 route->wpt_rec_id[gPrefs.act_rte.wpt_index]; 00799 00800 /* unlock route record */ 00801 MemHandleUnlock(routeDBEntry); 00802 00803 /* display new active waypoint */ 00804 display_wpt(&wpt_lat, &wpt_lon); 00805 00806 } else { 00807 gPrefs.act_wpt.valid = false; 00808 } /* if (!err) */ 00809 } /* if (gPrefs.act_rte.valid) */ 00810 } 00811 00812 if (eventP->eType == ctlSelectEvent) { 00813 if (eventP->data.ctlSelect.controlID == NavigationWptIDSel) { 00814 if (gPrefs.act_wpt.valid) { 00815 /* display active waypoint */ 00816 err = DmFindRecordByID(gWaypointDB, gPrefs.act_wpt.waypointID, 00817 &rec); 00818 00819 if (!err) { 00820 Char prox_str[10]; 00821 00822 /* active waypoint found */ 00823 waypointDBEntry = DmQueryRecord(gWaypointDB, rec); 00824 packed_waypoint = 00825 (packed_waypoint_t *)MemHandleLock(waypointDBEntry); 00826 UnpackWaypoint(&waypoint, packed_waypoint); 00827 MemSet((Char *)tmp, 7, 0); 00828 StrNCopy(tmp, (Char *)&waypoint.ident, 6); 00829 format_number(waypoint.dst, 0, prox_str); 00830 FrmCustomAlert(NavigationWptAlert, 00831 tmp, (Char *)waypoint.cmnt, prox_str); 00832 00833 MemHandleUnlock(waypointDBEntry); 00834 } /* if (!err) */ 00835 } /* if (gPrefs.act_wpt.valid) */ 00836 } /* if (eventP->data.ctlSelect.controlID == NavigationWptIDSel) */ 00837 00838 if (eventP->data.ctlSelect.controlID == NavigationRteIDSel) { 00839 if (gPrefs.act_rte.valid) { 00840 /* display active route */ 00841 err = DmFindRecordByID(gRouteDB, gPrefs.act_rte.routeID, 00842 &rec); 00843 00844 if (!err) { 00845 Char rte_str[4]; /* route items string */ 00846 Char wpt_str[16]; /* start/dst. waypoint ID string */ 00847 UInt16 i; /* loop index */ 00848 UInt16 n; /* last waypoint array index */ 00849 00850 /* clear string buffer */ 00851 MemSet((Char *)wpt_str, 16, 0); 00852 00853 /* active route found */ 00854 routeDBEntry = DmQueryRecord(gRouteDB, rec); 00855 00856 /* lock record */ 00857 route = (route_t *)MemHandleLock(routeDBEntry); 00858 00859 /* print route number to string */ 00860 StrPrintF(rte_str, "%-3d", route->items); 00861 00862 /* get destination waypoint's index*/ 00863 n = route->items-1; 00864 00865 /* do first index, last index */ 00866 for (i=0; i<=n; i+=n) { 00867 00868 /* get waypoint record ID from route record */ 00869 err = DmFindRecordByID(gWaypointDB, 00870 route->wpt_rec_id[i], &rec); 00871 00872 /* get waypoint record */ 00873 waypointDBEntry = DmQueryNextInCategory(gWaypointDB, &rec, 00874 dmAllCategories); 00875 00876 /* lock waypoint record */ 00877 packed_waypoint = 00878 (packed_waypoint_t *)MemHandleLock(waypointDBEntry); 00879 00880 /* unpack waypoint record */ 00881 UnpackWaypoint(&waypoint, packed_waypoint); 00882 00883 /* Copy Identifier to first/second half of buffer */ 00884 StrNCopy(&wpt_str[(i==0) ? 0 : 8], waypoint.ident, 6); 00885 00886 /* unlock waypoint record */ 00887 MemHandleUnlock(waypointDBEntry); 00888 } /* for (i=0; i<=n; i+=n) */ 00889 FrmCustomAlert(NavigationRteAlert, 00890 rte_str, wpt_str, &wpt_str[8]); 00891 00892 /* unlock route record */ 00893 MemHandleUnlock(routeDBEntry); 00894 } /*if (!err) */ 00895 } /* if (gPrefs.act_rte.valid) */ 00896 } /* if (eventP->data.ctlSelect.controlID == NavigationRteIDSel) */ 00897 } /* if (eventP->eType == ctlSelectEvent) */ 00898 handled = true; 00899 break; 00900 00901 case nilEvent: 00902 handled = true; 00903 00904 /* throw away anything in the buffer-- we want fresh data */ 00905 DoReceiveFlush(gPortID, 1); 00906 00907 /* 00908 * Get GPS Data and update compass (COG) 00909 */ 00910 updatedDisplay = ReadFromGPS(); 00911 00912 if (gHdFtrSet) { 00913 WinPushDrawState(); 00914 WinSetCoordinateSystem(kCoordinatesNative); 00915 } 00916 00917 /* 00918 * Remove old pointer 00919 */ 00920 r = (gHdFtrSet) ? WinScaleCoord(NAV_R1 - 5, false) : NAV_R1 - 5; 00921 p1.x = (gHdFtrSet) ? WinScaleCoord(NAV_X, false) : NAV_X; 00922 p1.y = (gHdFtrSet) ? WinScaleCoord(NAV_Y, false) : NAV_Y; 00923 x = p1.x + r * icos(otrk) / 32768; 00924 y = p1.y + r * isin(otrk) / 32768; 00925 00926 WinEraseLine(p1.x, p1.y, x, y); 00927 00928 if (gHdFtrSet) { 00929 WinPopDrawState(); 00930 } 00931 00932 if (gGPSData.valid) { 00933 00934 /* Speed Over Ground */ 00935 display_sog(); 00936 00937 /* Course Made Good (= Course Over Ground = Track) */ 00938 display_cmg(); 00939 00940 } else { 00941 SetFieldText(NavigationSogField, NULL, false, true); 00942 SetFieldText(NavigationCmgField, NULL, false, true); 00943 } /* if (gGPSData.valid) */ 00944 00945 if (gGPSData.valid && gPrefs.act_rte.valid && gPrefs.auto_wpt) { 00946 if ( UpdateActWpt(gGPSData.lat, gGPSData.lon, false /* init */) ) { 00947 /* update and display new active waypoint */ 00948 display_wpt(&wpt_lat, &wpt_lon); 00949 } 00950 } 00951 00952 /* Active Waypoint approach detection and display */ 00953 NotifyApproach(); 00954 00955 /* Track Logging */ 00956 if (gPrefs.act_trk.log_state) { 00957 Boolean new_trk; 00958 00959 if (TrackIntervalCheck(false /* init */, &new_trk)) { 00960 TrackWriteLog(new_trk); 00961 } 00962 } 00963 00964 if (gGPSData.valid && gPrefs.act_wpt.valid) { 00965 Char brg_str[8]; 00966 00967 /* 00968 * Distance to Waypoint 00969 */ 00970 dist = gc_dist_sphere(gGPSData.lat, gGPSData.lon, wpt_lat, wpt_lon); 00971 00972 /* calculate distance in km */ 00973 dist = dist * calcR(gGPSData.lat) / 1000.0; 00974 display_dst(dist); 00975 00976 /* 00977 * Bearing (= Direction to Waypoint) 00978 */ 00979 brg = gc_course_sphere(gGPSData.lat, gGPSData.lon, wpt_lat, wpt_lon); 00980 brg = rad2deg(brg); 00981 00982 /* 00983 * Turn = bearing - track (pos: right/neg: left) 00984 */ 00985 turn = brg - gGPSData.cmg; 00986 display_trn(turn); 00987 00988 trk = (Int32)turn - 90; 00989 00990 format_number(brg, 1, brg_str); 00991 StrCat(brg_str, "°"); 00992 SetFieldText(NavigationBrgField, brg_str, false, true); 00993 00994 if (gHdFtrSet) { 00995 WinPushDrawState(); 00996 WinSetCoordinateSystem(kCoordinatesNative); 00997 } 00998 00999 /* 01000 * Draw new pointer 01001 */ 01002 r = (gHdFtrSet) ? WinScaleCoord(NAV_R1 - 5, false) : NAV_R1 - 5; 01003 p1.x = (gHdFtrSet) ? WinScaleCoord(NAV_X, false) : NAV_X; 01004 p1.y = (gHdFtrSet) ? WinScaleCoord(NAV_Y, false) : NAV_Y; 01005 x = p1.x + r * icos(trk) / 32768; 01006 y = p1.y + r * isin(trk) / 32768; 01007 01008 WinDrawLine(p1.x, p1.y, x, y); 01009 01010 if (gHdFtrSet) { 01011 WinPopDrawState(); 01012 } 01013 01014 /* save old track */ 01015 otrk = trk; 01016 01017 /* velocity made good: velocity in direction to waypoint (in kts) */ 01018 vmg = gGPSData.sog * cos( deg2rad(turn) ); 01019 01020 /* 01021 * VMG is negative if leaving waypoint. Additionally, 01022 * we set a threshold (0.5 kts) to determine if we are 01023 * really approaching the waypoint. 01024 */ 01025 if (vmg > 0.5) { 01026 UInt16 h; 01027 UInt16 m; 01028 UInt16 s; 01029 Char ttg_str[10]; /* 999:59:59 */ 01030 01031 display_vmg(vmg); 01032 01033 /* 01034 * time to go: dist / vmg 01035 * Averaging VMG would yield more meaningful results... 01036 */ 01037 ttg = dist / (vmg * spd_c[SPD_KMH].conv); 01038 01039 hours_to_hms(ttg, &h, &m, &s); 01040 01041 if (h < 999) { 01042 StrPrintF(ttg_str, "%u:%02u:%02u", h, m, s); 01043 SetFieldText(NavigationTtgField, ttg_str, false, true); 01044 } else { 01045 /* 01046 * More than 999 hours are considered to be an overflow, 01047 * due to limited screen space. And most likely the result 01048 * will be inaccurate, anyway... 01049 */ 01050 SetFieldText(NavigationTtgField, "Overflow", false, true); 01051 } 01052 } else { 01053 /* leaving waypoint or not moving */ 01054 SetFieldText(NavigationVmgField, "--", false, true); 01055 SetFieldText(NavigationTtgField, "--:--:--", false, true); 01056 } /* if (vmg > 1) */ 01057 } else { 01058 /* no active WPT or GPS invalid */ 01059 SetFieldText(NavigationDstField, NULL, false, true); 01060 SetFieldText(NavigationBrgField, NULL, false, true); 01061 SetFieldText(NavigationTrnField, NULL, false, true); 01062 SetFieldText(NavigationVmgField, NULL, false, true); 01063 SetFieldText(NavigationTtgField, NULL, false, true); 01064 } /* if (gGPSData.valid && gPrefs.act_wpt.valid) */ 01065 break; 01066 01067 case frmCloseEvent: 01068 /* Deallocate Fields' Text Memory */ 01069 SetFieldText(NavigationStatusField, NULL, false, true); 01070 SetFieldText(TimeField, NULL, false, true); 01071 SetFieldText(NavigationDstField, NULL, false, true); 01072 SetFieldText(NavigationSogField, NULL, false, true); 01073 SetFieldText(NavigationVmgField, NULL, false, true); 01074 SetFieldText(NavigationTtgField, NULL, false, true); 01075 SetFieldText(NavigationCmgField, NULL, false, true); 01076 SetFieldText(NavigationBrgField, NULL, false, true); 01077 SetFieldText(NavigationTrnField, NULL, false, true); 01078 WinDeleteWindow(gNavigationH, true /* eraseIt */); 01079 break; 01080 01081 } 01082 return(handled); 01083 } /* NavigationFormHandleEvent() */