GPS4Palm

Source Code Documentation


Data.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * $RCSfile: Data_8c-source.html,v $
00004  *
00005  * GPS4Palm Data Base Functions
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:32 $
00015  *
00016  * $Revision: 1.7.2.1 $
00017  *
00018  * $Log: Data_8c-source.html,v $
00018  * Revision 1.7.2.1  2007-10-08 20:40:32  mp
00018  * updated for gps4palm V0.9.5 beta
00018  *
00019  * Revision 1.23  2005-04-02 17:55:16  mp
00020  * removed test code
00021  *
00022  * Revision 1.22  2005/04/02 17:28:21  mp
00023  * added CompareStringFunc() and Position2Geodb(), removed CompareIDFunc()
00024  *
00025  * Revision 1.21  2005/02/05 17:33:42  mp
00026  * added DeleteTracks()
00027  *
00028  * Revision 1.20  2004/12/12 21:01:08  mp
00029  * fixed track log wrap around
00030  *
00031  * Revision 1.19  2004/12/10 19:52:23  mp
00032  * replaced DmGet1Resource by DmGetResource
00033  *
00034  * Revision 1.18  2004/12/09 17:32:44  mp
00035  * replaced default track comment string by string resource,
00036  * implemented wrapping when track log database full
00037  *
00038  * Revision 1.17  2004/12/08 20:51:07  mp
00039  * added TrackIntervalCheck()
00040  *
00041  * Revision 1.16  2004/12/07 18:51:09  mp
00042  * added TrackWriteLog()
00043  *
00044  * Revision 1.15  2004/12/04 09:40:49  mp
00045  * added gTrackHdrDB, StoreTrkHdr(), StoreTrkPoint(), TrackDBName(), and
00046  * TrackIdent()
00047  *
00048  * Revision 1.14  2004/11/27 10:16:08  mp
00049  * replaced ErrFatalDisplay() by Die() for memory allocation failures
00050  *
00051  * Revision 1.13  2004/11/25 20:04:45  mp
00052  * added NotifyApproach()
00053  *
00054  * Revision 1.12  2004/11/25 16:59:22  mp
00055  * added CheckApproach()
00056  *
00057  * Revision 1.11  2004/11/24 21:03:43  mp
00058  * modified error handling in UpdateActWpt()
00059  *
00060  * Revision 1.10  2004/11/23 17:53:09  mp
00061  * removed unused variable
00062  *
00063  * Revision 1.9  2004/11/20 15:53:12  mp
00064  * added UpdateActWpt()
00065  *
00066  * Revision 1.8  2004/11/17 19:47:10  mp
00067  * code cleanup
00068  *
00069  * Revision 1.7  2004/11/16 21:05:53  mp
00070  * modified route/waypoint record write functions: pass record index instead
00071  * of handle, this allows to call DmGetRecord() / DmReleaseRecord
00072  *
00073  * Revision 1.6  2004/11/16 19:21:40  mp
00074  * added InsertRouteWpt(), DelRouteWpt(), and MoveRouteWpt(),
00075  * modified PackWaypoint() (removed debug output)
00076  *
00077  * Revision 1.5  2004/06/23 17:58:14  mp
00078  * Added comments, removed example functions from Sales application.
00079  *
00080  * Revision 1.4  2004/04/21 18:34:36  mp
00081  * modified macro DEG2SEMI()
00082  *
00083  * Revision 1.3  2004/03/12 21:16:26  mp
00084  * added InitializeWaypoints(void)
00085  *
00086  * Revision 1.2  2004/03/10 17:23:37  mp
00087  * modified due to changes in Data.h
00088  *
00089  * Revision 1.1  2004/03/07 14:28:49  mp
00090  * initial version
00091  *
00092  *
00093  ****************************************************************************/
00094 #include <PalmOS.h>
00095 #include "Garmin.h"
00096 #include "Data.h"
00097 #include "geo.h"                /* gc_dist_sphere() */
00098 #include "common.h"
00099 #include "gpslib.h"             /* Palm2GarminTimeDiff */
00100 #include "Utils.h"
00101 #include "ResourceDefines.h"
00102 
00103 /** Convert degrees (double) to semicircles (fix-point) */
00104 #define DEG2SEMI(x)     ((G_long)(x * ((1UL<<31)/180.0)))
00105 
00106 /* Global Variables */
00107 DmOpenRef       gWaypointDB;            /**< Waypoint Database Reference */
00108 DmOpenRef       gRouteDB;               /**< Route Database Reference */
00109 DmOpenRef       gTrackHdrDB;            /**< Track Header Database Reference */
00110 DmOpenRef       gTrackDB = 0;           /**< Track Database Reference */
00111 
00112 extern PrefsType        gPrefs;         /* Preferences data structure */
00113 extern GPSType          gGPSData;       /* GPS Data */
00114 
00115 /*
00116  * Track Log time interval in seconds
00117  *   (must match TrkIntTimeList in GPS4Palm.rcp)
00118  */
00119 static const UInt16 log_interval_time[] = {
00120   1, 2, 5, 10, 20, 30, 60, 120
00121 };
00122 
00123 /*
00124  * Track Log distance interval in meters
00125  *   (must match TrkIntDstList in GPS4Palm.rcp)
00126  */
00127 static const UInt16 log_interval_dist[] = {
00128   10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000
00129 };
00130 
00131 /* Memo Name (keep it short, this has to be entered by the user in GeoDB) */
00132 static const Char memo_name[] = "Gps4";
00133 
00134 /* Location Name (has to be edited anyway) */
00135 static const Char location_name[] = "_GPS4Palm";
00136 
00137 
00138 /*****************************************************************************
00139  * FUNCTION:    CheckDatabases
00140  *
00141  * DESCRIPTION: Check lock state of databases.
00142  *
00143  * PARAMETERS:  %
00144  *
00145  * RETURNED:    %
00146  ****************************************************************************/
00147 #ifdef DEBUG_BUILD
00148 void CheckDatabases(void)
00149 {
00150   UInt8         highest;
00151   UInt32        count;
00152   UInt32        busy;
00153   
00154   return;
00155   DmGetDatabaseLockState(gWaypointDB, &highest, &count, &busy);
00156   if (highest || busy)
00157     ErrFatalDisplay("Waypoint db not quiescent");
00158   DmGetDatabaseLockState(gRouteDB, &highest, &count, &busy);
00159   if (highest || busy)
00160     ErrFatalDisplay("Route db not quiescent");
00161   DmGetDatabaseLockState(gTrackDB, &highest, &count, &busy);
00162   if (highest || busy)
00163     ErrFatalDisplay("Track db not quiescent");
00164 }
00165 #endif
00166 
00167 
00168 /****************************************************************************/
00169 /**
00170  * \brief       Compare Strings
00171  *
00172  *
00173  * PARAMETERS:  see DmComparF() in PalmOS Reference
00174  *
00175  * \return
00176  *              - -1 if str1 < str2
00177  *              -  1 if str1 > str2
00178  *              -  0 if str1 = str2
00179  ****************************************************************************/
00180 Int16 CompareStringFunc(const Char *str1, const Char *str2, Int16 i, 
00181   SortRecordInfoPtr s1, SortRecordInfoPtr s2, MemHandle appInfoH)
00182 {
00183   return StrCompare(str1, str2);
00184 }
00185 
00186 
00187 /****************************************************************************/
00188 /**
00189  * \brief       Compare Waypoint Identifiers
00190  *
00191  * \note        The identifiers are not necessarily null-terminated,
00192  *                therefore StrCompare() cannot be used.
00193  *
00194  * PARAMETERS:  see DmComparF() in PalmOS Reference
00195  *
00196  * \return
00197  *              - -1 if ident1 < ident2
00198  *              -  1 if ident1 > ident2
00199  *              -  0 if ident1 = ident2
00200  ****************************************************************************/
00201 Int16 CompareWayptIdent(waypoint_t *rec1, packed_waypoint_t *rec2,
00202   Int16 i, SortRecordInfoPtr s1, SortRecordInfoPtr s2, MemHandle appInfoH)
00203 {
00204   #pragma unused(i, s1, s2, appInfoH)
00205   UInt16        n;
00206   
00207   for (n=0; n<6; n++) {
00208     if (rec1->ident[n] < rec2->ident[n]) {
00209       return -1;
00210     } else if (rec1->ident[n] > rec2->ident[n]) {
00211       return 1;
00212     } else if ((rec1->ident[n] == '\0') && (rec2->ident[n] == '\0')) {
00213       break;
00214     }
00215   }
00216   
00217   /* Identifiers are equal */
00218   return 0;
00219 }
00220 
00221 
00222 /****************************************************************************/
00223 /**
00224  * \brief       Compare Route Numbers
00225  *
00226  * \note        see DmComparF() in PalmOS Reference for parameters
00227  *
00228  * \return
00229  *              - -1 if nmbr1 < nmbr2
00230  *              -  1 if nmbr1 > nmbr2
00231  *              -  0 if nmbr1 = nmbr2
00232  ****************************************************************************/
00233 Int16 CompareRteNmbr(route_t *rec1, route_t *rec2,
00234   Int16 i, SortRecordInfoPtr s1, SortRecordInfoPtr s2, MemHandle appInfoH)
00235 {
00236   #pragma unused(i, s1, s2, appInfoH)
00237   
00238   if (rec1->nmbr < rec2->nmbr) {
00239     return -1;
00240   } else if (rec1->nmbr > rec2->nmbr) {
00241     return 1;
00242   }
00243   
00244   /* Identifiers are equal */
00245   return 0;
00246 }
00247 
00248 
00249 
00250 /****************************************************************************/
00251 /**
00252  * \brief       Pack Waypoint and store it in Database
00253  *
00254  * \param       waypoint                ptr to waypoint structure
00255  * \param       index                   waypoint record index
00256  *
00257  ****************************************************************************/
00258 void PackWaypoint(waypoint_t *waypoint, UInt16 index)
00259 {
00260   MemHandle     waypointDBEntry;        /* waypoint record handle */
00261   UInt16        length = 0;             /* record length */
00262   Char          *s;                     /* record ptr */
00263   UInt16        offset = 0;             /* offset into record */
00264   
00265   /* get waypoint record */
00266   waypointDBEntry = DmGetRecord(gWaypointDB, index);
00267   
00268   /* figure out necessary size */
00269   length = (UInt16) (   sizeof(waypoint->ident) +
00270                         sizeof(waypoint->posn) +
00271                         sizeof(waypoint->dst) +
00272                         sizeof(waypoint->smbl) +
00273                         sizeof(waypoint->dspl) +
00274                         StrLen(waypoint->cmnt) +
00275                         1 /* 1 for string terminator */
00276                     );
00277 
00278   /* resize the MemHandle */
00279   if (MemHandleResize(waypointDBEntry, length) == 0) {
00280     /* copy the fields */
00281     s = (Char *) MemHandleLock(waypointDBEntry);
00282     offset = 0;
00283     DmWrite(s, offset, &waypoint->ident,
00284       sizeof(waypoint->ident));
00285     offset += sizeof(waypoint->ident);
00286     DmWrite(s, offset, &waypoint->posn.lat,
00287       sizeof(waypoint->posn.lat));
00288     offset += sizeof(waypoint->posn.lat);
00289     DmWrite(s, offset, &waypoint->posn.lon,
00290       sizeof(waypoint->posn.lon));
00291     offset += sizeof(waypoint->posn.lon);
00292     DmWrite(s, offset, &waypoint->dst,
00293       sizeof(waypoint->dst));
00294     offset += sizeof(waypoint->dst);
00295     DmWrite(s, offset, &waypoint->smbl,
00296       sizeof(waypoint->smbl));
00297     offset += sizeof(waypoint->smbl);
00298     DmWrite(s, offset, &waypoint->dspl,
00299       sizeof(waypoint->dspl));
00300     offset += sizeof(waypoint->dspl);
00301     DmStrCopy(s, offset, waypoint->cmnt);
00302     MemHandleUnlock(waypointDBEntry);
00303   } else {
00304     Die("Cannot resize waypoint DB record!");
00305   }
00306   
00307   /* release record */
00308   DmReleaseRecord(gWaypointDB, index, true /* dirty */);
00309 }
00310 
00311 
00312 /****************************************************************************/
00313 /**
00314  * \brief       Store Route Header in Database
00315  *
00316  * \param       route           ptr to route structure
00317  * \param       index           route record index
00318  *
00319  ****************************************************************************/
00320 void PackRouteHdr(route_t *route, UInt16 index)
00321 {
00322   MemHandle     routeDBEntry;   /* route record handle */
00323   UInt16        length = 0;     /* record length */
00324   Char          *s;             /* record ptr */
00325   UInt16        offset = 0;     /* offset into record */
00326   
00327   routeDBEntry = DmGetRecord(gRouteDB, index);
00328   
00329   /* figure out necessary size */
00330   length = (UInt16) (   sizeof(route->nmbr) +
00331                         sizeof(route->cmnt) +
00332                         sizeof(route->items) +
00333                         route->items * sizeof(route->wpt_rec_id[0])
00334                     );
00335 
00336   /* resize the MemHandle */
00337   if (MemHandleResize(routeDBEntry, length) == 0) {
00338     /* copy the fields */
00339     s = (Char *)MemHandleLock(routeDBEntry);
00340     offset = 0;
00341 
00342     DmWrite(s, offset, &route->nmbr,
00343       sizeof(route->nmbr));
00344     offset += sizeof(route->nmbr);
00345     DmStrCopy(s, offset, route->cmnt);
00346     offset += sizeof(route->cmnt);
00347     DmWrite(s, offset, &route->items,
00348       sizeof(route->items));
00349     MemHandleUnlock(routeDBEntry);
00350   } else {
00351     Die("Cannot resize route DB record (header)!");
00352   }
00353 
00354   /* release record */
00355   DmReleaseRecord(gRouteDB, index, true /* dirty */);
00356 }
00357 
00358 
00359 /****************************************************************************/
00360 /**
00361  * \brief       Store Route Waypoint in Database (append)
00362  *
00363  * \param       wpt_rec_id      waypoint record ID
00364  * \param       index           route record index
00365  *
00366  ****************************************************************************/
00367 void PackRouteWpt(UInt32 wpt_rec_id, UInt16 index)
00368 {
00369   MemHandle     routeDBEntry;   /* route record handle */
00370   UInt16        items;          /* number of waypoints on route */
00371   UInt16        length = 0;     /* record length */
00372   UInt16        offset = 0;     /* offset into record */
00373   route_t       *route;         /* record ptr */
00374   
00375   /* get record handle */
00376   routeDBEntry = DmGetRecord(gRouteDB, index);
00377  
00378   /* figure out necessary size: original size + new wpt_rec_id */
00379   route = MemHandleLock(routeDBEntry);
00380   items = route->items + 1;
00381   MemHandleUnlock(routeDBEntry);
00382   
00383   length = (UInt16) (   sizeof(route->nmbr) +
00384                         sizeof(route->cmnt) +
00385                         sizeof(route->items) +
00386                         (sizeof(route->wpt_rec_id[0]) * items)
00387                     );
00388     
00389   /* resize the MemHandle */
00390   if (MemHandleResize(routeDBEntry, length) == 0) {
00391     /* copy the fields */
00392     route = MemHandleLock(routeDBEntry);
00393     offset = length - sizeof(route->wpt_rec_id[0]);
00394     DmWrite(route, offset, &wpt_rec_id,
00395       sizeof(wpt_rec_id));
00396     
00397     DmWrite(route, OffsetOf(route_t, items), &items, sizeof(route->items));
00398     MemHandleUnlock(routeDBEntry);
00399   } else {
00400     Die("Cannot resize route DB record (waypoints)!");
00401   }
00402 
00403   /* release record */
00404   DmReleaseRecord(gRouteDB, index, true /* dirty */);
00405 }
00406 
00407 
00408 /****************************************************************************/
00409 /**
00410  * \brief       Store Route Waypoint in Database (insert after selection)
00411  *
00412  * \param       rec             route record index
00413  * \param       wpt_rec_id      waypoint record ID
00414  * \param       wpt_index       waypoint array index
00415  *
00416  ****************************************************************************/
00417 void InsertRouteWpt(UInt16 rec, UInt32 wpt_rec_id, UInt16 wpt_index)
00418 {
00419   MemHandle     routeDBEntry;   /* route record handle */
00420   route_t       *route;         /* route record ptr */
00421   UInt16        items;          /* no. of waypoints */
00422   UInt16        length;         /* length of record */
00423   UInt16        offset;         /* offset within record */
00424   UInt16        i;              /* loop index */
00425   
00426   /* get record handle */
00427   routeDBEntry = DmGetRecord(gRouteDB, rec);
00428   
00429   /* figure out necessary size: original size + new wpt_rec_id */
00430   route = MemHandleLock(routeDBEntry);
00431   items = route->items + 1;
00432   MemHandleUnlock(routeDBEntry);
00433   
00434   length = (UInt16) (   sizeof(route->nmbr) +
00435                         sizeof(route->cmnt) +
00436                         sizeof(route->items) +
00437                         (sizeof(route->wpt_rec_id[0]) * items)
00438                     );
00439   
00440   /* set offset to last item */
00441   offset = length - sizeof(route->wpt_rec_id[0]);
00442   
00443   /* resize the MemHandle */
00444   if (MemHandleResize(routeDBEntry, length) == 0) {
00445     /* lock record handle */
00446     route = MemHandleLock(routeDBEntry);
00447     
00448     /* move array items down */
00449     for (i=items-1; i>wpt_index+1; i--) {
00450       DmWrite(route, offset, &route->wpt_rec_id[i-1],
00451         sizeof(route->wpt_rec_id[i-1]));
00452       offset -= sizeof(route->wpt_rec_id[0]);
00453     }
00454 
00455     /* write new item */
00456     DmWrite(route, offset, &wpt_rec_id, sizeof(wpt_rec_id));
00457    
00458     /* store new number of items */
00459     DmWrite(route, OffsetOf(route_t, items), &items, sizeof(items));
00460 
00461     /* unlock record handle */
00462     MemHandleUnlock(routeDBEntry);
00463 
00464   } else {
00465     Die("Cannot resize route DB record (waypoints)!");
00466   }
00467   
00468   /* release record */
00469   DmReleaseRecord(gRouteDB, rec, true /* dirty */);
00470 }
00471 
00472 
00473 /****************************************************************************/
00474 /**
00475  * \brief       Delete Route Waypoint from Database
00476  *
00477  * \param       rec             route record index
00478  * \param       wpt_index       waypoint array index
00479  *
00480  ****************************************************************************/
00481 void DelRouteWpt(UInt16 rec, UInt16 wpt_index)
00482 {
00483   MemHandle     routeDBEntry;   /* route record handle */
00484   route_t       *route;         /* route record ptr */
00485   UInt16        i;              /* loop index */
00486   UInt16        offset;         /* offset within record */
00487   UInt16        items;          /* new no. of items */
00488   UInt16        length = 0;     /* length of record */
00489   
00490   /* get record handle */
00491   routeDBEntry = DmGetRecord(gRouteDB, rec);
00492 
00493   /* offset to waypoint record ID to be deleted */
00494   offset = sizeof(route->nmbr) +
00495            sizeof(route->cmnt) +
00496            sizeof(route->items) +
00497            sizeof(route->wpt_rec_id[0]) * wpt_index;
00498     
00499   /* lock record */
00500   route = MemHandleLock(routeDBEntry);
00501   
00502   /* move array items up */
00503   for (i=wpt_index; i<route->items-1; i++) {
00504     DmWrite(route, offset, &route->wpt_rec_id[i+1],
00505       sizeof(route->wpt_rec_id[i+1]));
00506     offset += sizeof(route->wpt_rec_id[0]);    
00507   }
00508   
00509   /* calculate offset to route->items */
00510   offset = sizeof(route->nmbr) +
00511            sizeof(route->cmnt);
00512   
00513   /* new no. of items */
00514   items = route->items - 1;
00515   
00516   /* write new no. of items to record */
00517   DmWrite(route, offset, &items, sizeof(items));
00518   
00519   /* unlock record */
00520   MemHandleUnlock(routeDBEntry);
00521   
00522   /* release record */
00523   DmReleaseRecord(gRouteDB, rec, true /* dirty */);
00524   
00525   /* resize the MemHandle */
00526   length = (UInt16) (   sizeof(route->nmbr) +
00527                         sizeof(route->cmnt) +
00528                         sizeof(route->items) +
00529                         (sizeof(route->wpt_rec_id[0]) * items)
00530                     );
00531 
00532   MemHandleResize(routeDBEntry, length);
00533 }
00534 
00535 
00536 /****************************************************************************/
00537 /**
00538  * \brief       Move Route Waypoint in Database
00539  *
00540  * \param       rec             route record index
00541  * \param       wpt_index       waypoint array index
00542  * \param       up              direction: true - up / false - down
00543  *
00544  ****************************************************************************/
00545 void MoveRouteWpt(UInt16 rec, UInt16 wpt_index, Boolean up)
00546 {
00547   MemHandle     routeDBEntry;   /* route record handle */
00548   route_t       *route;         /* route record ptr */
00549   UInt16        offset;         /* offset within record */
00550   UInt32        wpt_rec_id;     /* unique waypoint record ID */
00551 
00552   /* get record handle */
00553   routeDBEntry = DmGetRecord(gRouteDB, rec);
00554 
00555   /* offset to waypoint record ID to be moved */
00556   offset = sizeof(route->nmbr) +
00557            sizeof(route->cmnt) +
00558            sizeof(route->items) +
00559            sizeof(route->wpt_rec_id[0]) * wpt_index;
00560     
00561   /* lock record */
00562   route = MemHandleLock(routeDBEntry);
00563   
00564   if (up) {
00565     wpt_rec_id = route->wpt_rec_id[wpt_index-1];
00566     DmWrite(route, offset-sizeof(wpt_rec_id),
00567       &route->wpt_rec_id[wpt_index], sizeof(wpt_rec_id));
00568     DmWrite(route, offset,
00569       &wpt_rec_id, sizeof(wpt_rec_id));
00570   } else {
00571     wpt_rec_id = route->wpt_rec_id[wpt_index+1];
00572     DmWrite(route, offset+sizeof(wpt_rec_id),
00573       &route->wpt_rec_id[wpt_index], sizeof(wpt_rec_id));
00574     DmWrite(route, offset,
00575       &wpt_rec_id, sizeof(wpt_rec_id));
00576   }
00577   
00578   /* unlock record */
00579   MemHandleUnlock(routeDBEntry);
00580 
00581   /* release record */
00582   DmReleaseRecord(gRouteDB, rec, true /* dirty */);
00583 }
00584 
00585 /**********************************************************************/
00586 /**
00587  * Unpack waypoint retrieved from database.
00588  *
00589  * \note        The packed_waypoint must remain locked while
00590  *              the waypoint is in use.
00591  * \param       waypoint        ptr to unpacked waypoint structure
00592  * \param       packed_waypoint ptr to packed waypoint structure
00593  *********************************************************************/
00594 void UnpackWaypoint(waypoint_t *waypoint,
00595   const packed_waypoint_t *packed_waypoint)
00596 {
00597   StrNCopy(waypoint->ident, packed_waypoint->ident, 6);
00598   waypoint->posn.lat = packed_waypoint->posn.lat;
00599   waypoint->posn.lon = packed_waypoint->posn.lon;
00600   waypoint->unused = 0;
00601   waypoint->dst = packed_waypoint->dst;
00602   waypoint->smbl = packed_waypoint->smbl;
00603   waypoint->dspl = packed_waypoint->dspl;
00604   StrCopy(waypoint->cmnt, packed_waypoint->cmnt);
00605 }
00606 
00607 /**********************************************************************/
00608 /**
00609  * Store track header in database.
00610  *
00611  * \param       trkhdr          ptr to track header structure
00612  * \param       index           track header record index
00613  **********************************************************************/
00614 void StoreTrkHdr(trk_header_t *trkhdr, UInt16 index)
00615 {
00616   MemHandle     trkhDBEntry;    /* track point record handle */
00617   UInt16        length = 0;     /* record length */
00618   UInt16        offset = 0;     /* offset into record */
00619   trk_header_t  *trkP;          /* record ptr */  
00620 
00621   length = (UInt16) (   sizeof(trkhdr->dspl) +
00622                         sizeof(trkhdr->color) +
00623                         sizeof(trkhdr->trk_ident)
00624                     );  
00625 
00626   /* get record handle */
00627   trkhDBEntry = DmGetRecord(gTrackHdrDB, index);  
00628   
00629   /* resize the MemHandle */
00630   if (MemHandleResize(trkhDBEntry, length) == 0) {
00631     /* copy the fields */
00632     trkP = MemHandleLock(trkhDBEntry);
00633     offset = 0;
00634     DmWrite(trkP, offset, &trkhdr->dspl,
00635       sizeof(trkhdr->dspl));
00636     offset += sizeof(trkhdr->dspl);
00637     DmWrite(trkP, offset, &trkhdr->color,
00638       sizeof(trkhdr->color));
00639     offset += sizeof(trkhdr->color);
00640     DmWrite(trkP, offset, &trkhdr->trk_ident,
00641       sizeof(trkhdr->trk_ident));
00642     MemHandleUnlock(trkhDBEntry);
00643   } else {
00644     Die("Cannot resize track header DB record!");
00645   }
00646   
00647   /* release record */
00648   DmReleaseRecord(gTrackHdrDB, index, true /* dirty */);
00649 }
00650 
00651 
00652 /**********************************************************************/
00653 /**
00654  * Store track point in database.
00655  *
00656  * \param       trkpoint        ptr to track point structure
00657  * \param       index           track point record index
00658  **********************************************************************/
00659 void StoreTrkPoint(trk_point_t *trkpoint, UInt16 index)
00660 {
00661   MemHandle     trkpDBEntry;    /* track point record handle */
00662   UInt16        length = 0;     /* record length */
00663   UInt16        offset = 0;     /* offset into record */
00664   trk_point_t   *trkP;          /* record ptr */
00665 
00666   length = (UInt16) (   sizeof(trkpoint->posn) +
00667                         sizeof(trkpoint->time) +
00668                         sizeof(trkpoint->new_trk)
00669                     );  
00670 
00671   /* get record handle */
00672   trkpDBEntry = DmGetRecord(gTrackDB, index);
00673   
00674   /* resize the MemHandle */
00675   if (MemHandleResize(trkpDBEntry, length) == 0) {
00676     /* copy the fields */
00677     trkP = MemHandleLock(trkpDBEntry);
00678     offset = 0;
00679     DmWrite(trkP, offset, &trkpoint->posn,
00680       sizeof(trkpoint->posn));
00681     offset += sizeof(trkpoint->posn);
00682     DmWrite(trkP, offset, &trkpoint->time,
00683       sizeof(trkpoint->time));
00684     offset += sizeof(trkpoint->time);
00685     DmWrite(trkP, offset, &trkpoint->new_trk,
00686       sizeof(trkpoint->new_trk));
00687     MemHandleUnlock(trkpDBEntry);
00688   } else {
00689     Die("Cannot resize track point DB record!");
00690   }
00691   
00692   /* release record */
00693   DmReleaseRecord(gTrackDB, index, true /* dirty */);
00694 }
00695 
00696 
00697 /****************************************************************************/
00698 /**
00699  * \brief       Generate Track Point Data Base Name
00700  *
00701  * \param       dbname          pointer to destination string buffer
00702  * \param       trackID         track header unique record ID           
00703  *
00704  ****************************************************************************/
00705 void TrackDBName(Char *dbname, UInt32 trackID)
00706 {
00707   UInt16        i;                      /* loop index */
00708   
00709   /* copy fixed part of track data base name */
00710   StrPrintF(dbname, "%s", kTrkDBName);
00711   
00712   for (i=0; i<6; i++) {
00713     StrPrintF(&dbname[StrLen(dbname)], "%c", nibble2hex((trackID >> 20) & 0xF));
00714     trackID <<= 4;
00715   }
00716 }
00717 
00718 /****************************************************************************/
00719 /**
00720  * \brief       Generate Track Identifier from current Time and Date
00721  *
00722  * \param       ident           pointer to destination string buffer
00723  *
00724  ****************************************************************************/
00725 void TrackIdent(Char *ident)
00726 {
00727   UInt32        seconds;                /* current time */
00728   DateTimeType  dt;                     /* date/time structure */
00729   MemHandle     strH;                   /* string handle */ 
00730   MemPtr        strP;                   /* string ptr */
00731 
00732 
00733   /*
00734    * create comment: <Track yy-mm-dd hh:mm>
00735    */
00736   MemSet(ident, sizeof(ident), 0);
00737   
00738   /* get string from resource */
00739   strH = DmGetResource(strRsc, TrackStr);
00740   if (strH != NULL) {
00741     /* string handle valid, lock it */
00742     strP = MemHandleLock(strH);
00743   
00744     /* copy string */
00745     StrCopy(ident, strP);
00746 
00747     /* unlock string handle */
00748     MemHandleUnlock(strH);
00749 
00750     /* release string resource */
00751     DmReleaseResource(strH);
00752   }
00753   
00754   /* get current time and date */
00755   seconds = TimGetSeconds();
00756   TimSecondsToDateTime(seconds, &dt);
00757   
00758   /* write date to string */
00759   DateToAscii(dt.month, dt.day, dt.year, dfYMDWithDashes,
00760     &ident[StrLen(ident)]);
00761 
00762   /* append space */
00763   StrCat(ident, " ");
00764   
00765   /* write time to string */
00766   TimeToAscii(dt.hour, dt.minute, tfColon24h,
00767     &ident[StrLen(ident)]);
00768   
00769   /* append bracket */
00770   StrCat(ident, ">");
00771 }
00772 
00773 
00774 /****************************************************************************/
00775 /**
00776  * \brief       Delete all track point databases
00777  *
00778  ****************************************************************************/
00779 void DeleteTracks(void)
00780 {
00781   DmSearchStateType     state;          /* DmSearchState */
00782   UInt16                card;           /* card no. */
00783   LocalID               currentDB = 0;  /* local ID of current DB */
00784   Err                   err;            /* error code */
00785 
00786   do {
00787     err = DmGetNextDatabaseByTypeCreator(
00788       true /* newSearch */,
00789       &state /* stateInfoP */,
00790       kTrkDBType /* type */,
00791       kCreatorId /* creator */,
00792       false /* onlyLatestVers */,
00793       &card /* cardNoP */,
00794       &currentDB /* dbIDP */
00795     );
00796     
00797     if (!err) {
00798       DmDeleteDatabase(card, currentDB);
00799     }
00800   } while (!err);
00801 }
00802 
00803 
00804 /****************************************************************************/
00805 /**
00806  * \brief       Add Position to Memo for Import to GeoDB
00807  *
00808  * \param       gps_data        GPS Data (Time of Fix, Position, ...)
00809  *
00810  * \return      True if GPS data is valid.
00811  *
00812  * \note        GeoDB expects the following format in the Memo:
00813  *
00814  *              < memo_name >\n
00815  *              < location_name >,< latitude >,< N|S >,< longitude >,< E|W >,
00816  *              < elevation >,< gmt_offset >,< E|W >,< daylight_time >
00817  * 
00818  *              Example:
00819  * 
00820  *              AA
00821  *              Adana,37:0.6,N,35:16.8,E,,2,E,0
00822  *
00823  +              (GPS4Palm only knows the position)
00824  *
00825  ****************************************************************************/
00826 Boolean Position2Geodb(GPSType gps_data)
00827 {
00828   Char          clp_str[100];           /* clipboard string buffer */
00829   Char          lat_str[20];            /* latitude string buffer */
00830   Char          lon_str[20];            /* longitude string buffer */
00831   DmOpenRef     memoDB;
00832   MemHandle     recH;
00833   MemPtr        recP;
00834   UInt16        index;
00835 
00836   if (!gps_data.valid)
00837     return false;
00838  
00839   /* convert double lat/lon to string */
00840   deg_to_geodb_str(gps_data.lat, gps_data.lon, lat_str, lon_str);
00841   
00842   /*
00843    * TODO:
00844    * Elevation (or "Altitude") is actually known, but not a 
00845    * Member of GPSType yet.
00846    */
00847   
00848   /* format output string */
00849   StrPrintF(clp_str, "%s\n%s,%s,%s,,,,,",
00850     memo_name,
00851     location_name,
00852     lat_str,
00853     lon_str);
00854   
00855 /*
00856  * Note: optionally we could add it to clipboard  
00857   ClipboardAddItem(clipboardText, clp_str, StrLen(clp_str));
00858 */  
00859 
00860   /* Open Memo DB */
00861   memoDB = DmOpenDatabaseByTypeCreator('DATA', sysFileCMemo, dmModeReadWrite);
00862   
00863   /* Find sort position of new record in memo DB */  
00864   index = DmFindSortPosition(memoDB, clp_str, 0 /* newRecordInfo */,
00865     (DmComparF *)CompareStringFunc /* DmComparF *compar */, 0 /* other */);
00866 
00867   /* Create new memo record */
00868   recH = DmNewRecord(memoDB, &index, StrLen(clp_str) + 1);
00869   recP = MemHandleLock(recH);
00870   DmStrCopy(recP, 0, clp_str);
00871   MemHandleUnlock(recH);
00872   DmReleaseRecord(memoDB, index, true);
00873 
00874   /* Close Memo DB */
00875   DmCloseDatabase(memoDB);
00876 
00877   return true;
00878 }
00879 
00880 
00881 /****************************************************************************/
00882 /**
00883  * \brief       Update active (route) waypoint according to distance to
00884  *              current and next waypoint.
00885  *
00886  *              The current implementation switches to the next route
00887  *              waypoint even if the current waypoint is just "passed by",
00888  *              i.e. the distance to the current waypoint is increasing
00889  *              while the distance to the next waypoint is decreasing. 
00890  *
00891  *              A different implementation could require the current
00892  *              waypoint to be "visited" with the proximity information
00893  *              stored in the waypoint record as the criterion. 
00894  *
00895  * \param       lat             current latitude
00896  * \param       lon             current longitude
00897  * \param       init            initialize function (after changing route)      
00898  *
00899  * \return
00900  *              - true  if next waypoint has been select as active waypoint
00901  *              - false if current waypoint is still active waypoint
00902  *
00903  * \note        After changing the active route, the finction must be called
00904  *              with init=true (lat/lon may be invalid). This marks the
00905  *              distance values stored previously invalid. The next call
00906  *              which must occur with a valid position updates the stored
00907  *              distance values. Any subsequent call will then provide
00908  *              a correct waypoint selection.
00909  * 
00910  ****************************************************************************/
00911 Boolean UpdateActWpt(double lat, double lon, Boolean init)
00912 {
00913   route_t               *route;                 /* route */
00914   MemHandle             routeDBEntry;           /* route record handle */
00915   packed_waypoint_t     *packed_waypoint;       /* packed waypoint ptr */
00916   waypoint_t            waypoint;               /* unpacked waypoint */
00917   MemHandle             waypointDBEntry;        /* waypoint record handle */
00918   UInt16                rec;                    /* record index */
00919   static Boolean        init_ok = false;        /* flag: initialization o.k. */
00920   static double         dst_act_old;            /* old dist. to active wpt. */
00921   static double         dst_next_old;           /* dist. to next wpt. */
00922   double                dst_act;                /* dist. to active waypoint */
00923   double                dst_next;               /* dist. to next waypoint */
00924   double                wpt_lat;                /* waypoint longitude */
00925   double                wpt_lon;                /* waypoint latitude */
00926   Boolean               updated = false;        /* flag: act. wpt. updated */
00927   Err                   err;                    /* error code */
00928   
00929   if (init) {
00930     init_ok = false;
00931     return false;
00932   }
00933   
00934   /* get active route */
00935   err = DmFindRecordByID(gRouteDB, gPrefs.act_rte.routeID,
00936     &rec);
00937 
00938   if (!err) {
00939     /* active route found */
00940     routeDBEntry = DmQueryRecord(gRouteDB, rec);
00941     
00942     /* lock route record */
00943     route = (route_t *)MemHandleLock(routeDBEntry);
00944     
00945     if (gPrefs.act_rte.wpt_index == route->items-1) {
00946       /* last waypoint already active */
00947       MemHandleUnlock(routeDBEntry);
00948       return false;
00949     }
00950     
00951     /* get active waypoint */
00952     err = DmFindRecordByID(gWaypointDB,
00953       route->wpt_rec_id[gPrefs.act_rte.wpt_index],
00954       &rec);
00955 
00956     if (!err) {
00957       /* active waypoint found */
00958       waypointDBEntry = DmQueryRecord(gWaypointDB, rec);
00959       packed_waypoint =
00960         (packed_waypoint_t *)MemHandleLock(waypointDBEntry);
00961       UnpackWaypoint(&waypoint, packed_waypoint);
00962 
00963       wpt_lat = semi2deg(waypoint.posn.lat);
00964       wpt_lon = semi2deg(waypoint.posn.lon);
00965 
00966       MemHandleUnlock(waypointDBEntry);
00967       dst_act = gc_dist_sphere(lat, lon, wpt_lat, wpt_lon);
00968     } else {
00969       return false;
00970     }
00971     
00972     /* get next waypoint */
00973     err = DmFindRecordByID(gWaypointDB,
00974       route->wpt_rec_id[gPrefs.act_rte.wpt_index + 1],
00975       &rec);
00976       
00977     if (!err) {
00978       /* next waypoint found */
00979       waypointDBEntry = DmQueryRecord(gWaypointDB, rec);
00980       packed_waypoint =
00981         (packed_waypoint_t *)MemHandleLock(waypointDBEntry);
00982       UnpackWaypoint(&waypoint, packed_waypoint);
00983 
00984       wpt_lat = semi2deg(waypoint.posn.lat);
00985       wpt_lon = semi2deg(waypoint.posn.lon);
00986 
00987       MemHandleUnlock(waypointDBEntry);
00988       dst_next = gc_dist_sphere(lat, lon, wpt_lat, wpt_lon);
00989     } else {
00990       return false;
00991     }    
00992     
00993     if (init_ok && (dst_act > dst_act_old) && (dst_next < dst_next_old)) {
00994       /* next waypoint selected */
00995       gPrefs.act_rte.wpt_index++;
00996 
00997       /* update active waypoint record ID */
00998       gPrefs.act_wpt.waypointID = 
00999         route->wpt_rec_id[gPrefs.act_rte.wpt_index];
01000       updated = true;
01001 
01002     } else {
01003       /* current waypoint still active */
01004       updated = false;
01005     }
01006 
01007     /* save current distances */
01008     dst_act_old  = dst_act;
01009     dst_next_old = dst_next;
01010     init_ok = true;
01011   
01012     /* unlock route record */
01013     MemHandleUnlock(routeDBEntry);
01014   } /* if (!err) */
01015   
01016   return updated;
01017 }
01018 
01019 
01020 /****************************************************************************/
01021 /**
01022  * \brief       Write Track Point to Track Log Data Base
01023  *
01024  * \param       new_trk         new track or track segment
01025  *
01026  * \return      - true  if successful
01027  *              - false if data base is full and wrapping is disabled
01028  ****************************************************************************/
01029 Boolean TrackWriteLog(Boolean new_trk)
01030 {
01031   Char          dbname[dmDBNameLength]; /* data base name */
01032   MemHandle     trkDBEntry;             /* record handle */
01033   UInt16        index;                  /* record index */
01034   trk_point_t   trkpoint;               /* track point */
01035   
01036   if (!gTrackDB) {
01037     /* data base not yet open */
01038 
01039     /* generate data base name */
01040     TrackDBName(dbname, gPrefs.act_trk.trackID);
01041 
01042     /* open track DB */
01043     gTrackDB = DmOpenDatabase(0 /* cardNo */,
01044       DmFindDatabase(0 /* cardNo */, dbname), dmModeReadWrite);
01045   }
01046   
01047   if ( DmNumRecords(gTrackDB) < dmMaxRecordIndex) {
01048   
01049     /* add at the end of the database */
01050     index = dmMaxRecordIndex;
01051   
01052     trkDBEntry = DmNewRecord(gTrackDB, &index, sizeof(trk_point_t));
01053     
01054     if (trkDBEntry) {
01055       DmReleaseRecord(gTrackDB, index, false /* dirty */);
01056     } else {
01057       Die("Cannot create track record!");
01058       return false;
01059     }
01060     
01061   } else {
01062     /* Data Base is full */
01063     
01064     if (!gPrefs.trk_log.wrap) {
01065       /* stop or wrap */
01066       if (FrmAlert(TrackFullAlert) == 1) {
01067         /* change to wrapping */
01068         gPrefs.trk_log.wrap = true;
01069       }
01070     }
01071 
01072     if (gPrefs.trk_log.wrap) {
01073       /* wrap around */
01074 
01075       /* delete first record, overwrite last record */
01076       DmRemoveRecord(gTrackDB, 0);
01077       
01078       /* add at the end of the database */
01079       index = dmMaxRecordIndex;
01080 
01081       /* seek last record (will be overwritten) */ 
01082       DmSeekRecordInCategory(gTrackDB, &index, 0 /* offset */,
01083         dmSeekBackward, dmAllCategories);
01084 
01085     } else {
01086       /* stop logging */
01087       gPrefs.act_trk.log_state = false;
01088       gPrefs.act_trk.valid     = false;
01089       DmCloseDatabase(gTrackDB);
01090       return false;
01091 
01092     }
01093   }
01094   
01095   /* copy track point data to struct */
01096   trkpoint.new_trk  = new_trk;
01097   trkpoint.posn.lat = deg2semi(gGPSData.lat);
01098   trkpoint.posn.lon = deg2semi(gGPSData.lon);
01099   trkpoint.time     = gGPSData.time - Palm2GarminTimeDiff;
01100   
01101   /* store track point in DB */
01102   StoreTrkPoint(&trkpoint, index);
01103 
01104   return true;
01105 }
01106 
01107 
01108 /****************************************************************************/
01109 /**
01110  * \brief       check if track log interval reached
01111  *
01112  *              Checks if a new track point has to be logged depending on
01113  *              the selected track log mode (time or distance) and interval. 
01114  *              A new track segment is started upon initialization or after
01115  *              loosing and regaining coverage. 
01116  *
01117  * \param       init            init track interval accumulation and
01118  *                              start new track segment
01119  * \param       new_trk         new track segment (returned by reference)
01120  *
01121  * \return
01122  *              - true  if track point log interval passed
01123  *              - false if track point log interval not yet passed
01124  * 
01125  ****************************************************************************/
01126 Boolean TrackIntervalCheck(Boolean init, Boolean *new_trk)
01127 {
01128   static Boolean        gps_valid;              /* GPS fix valid */
01129   static UInt16         acc_time;               /* accumulated time */
01130   static UInt16         acc_dist;               /* accumulated distance */
01131   static UInt32         prev_time;              /* previous time */
01132   static double         prev_lat;               /* previous latitude */
01133   static double         prev_lon;               /* previous longitude */ 
01134   static Boolean        init_flag = true;       /* flag: init */
01135   Boolean               log_now = false;        /* flag: log now */
01136   
01137   if (init || (gps_valid == false && gGPSData.valid)) {
01138     /* start new track segment as soon as GPS fix available */
01139     init_flag = true;
01140     acc_time  = 0;
01141     acc_dist  = 0;
01142   }
01143   
01144   if (gGPSData.valid) {
01145     if (init_flag) {
01146       *new_trk  = true;
01147       log_now   = true;
01148       init_flag = false;
01149     } else {
01150       *new_trk = false;
01151       
01152       if (gPrefs.trk_log.mode == 1) {
01153         /* log interval mode: time */
01154         acc_time += TimGetSeconds() - prev_time;
01155         
01156         if (acc_time >= log_interval_time[gPrefs.trk_log.ival]) {
01157           acc_time = 0;
01158           log_now = true;
01159         }
01160         
01161       } else {
01162         /* log interval mode: distance */
01163         acc_dist += (UInt16)(gc_dist_sphere(gGPSData.lat, gGPSData.lon,
01164           prev_lat, prev_lon) * calcR(gGPSData.lat));
01165 
01166         if (acc_dist >= log_interval_dist[gPrefs.trk_log.ival]) {
01167           acc_dist = 0;
01168           log_now = true; 
01169         }
01170         
01171       } /* if (gPrefs.trk_log.mode == 0) */
01172     } /* if (*new_trk) */
01173     
01174     /* save current position */
01175     prev_lat  = gGPSData.lat;
01176     prev_lon  = gGPSData.lon;
01177     
01178     /* save current time */
01179     prev_time = TimGetSeconds();
01180   } /* if (gGPSData.valid) */
01181   
01182   /* save current GPS fix state */
01183   gps_valid = gGPSData.valid;
01184   
01185   return log_now;  
01186 }
01187 
01188 
01189 /****************************************************************************/
01190 /**
01191  * \brief       check if active waypoint is within proximity distance
01192  *
01193  *              If no proximity distance is stored in the waypoint data base
01194  *              (i.e. the proximity distance is zero), a default value is
01195  *              used. 
01196  *
01197  * \param       lat             current latitude
01198  * \param       lon             current longitude
01199  *
01200  * \return
01201  *              - true  if active waypoint is within proximity distance
01202  *              - false if active waypoint is not within proximity distance
01203  * 
01204  ****************************************************************************/
01205 Boolean CheckApproach(double lat, double lon)
01206 {
01207   packed_waypoint_t     *packed_waypoint;       /* packed waypoint ptr */
01208   waypoint_t            waypoint;               /* unpacked waypoint */
01209   MemHandle             waypointDBEntry;        /* waypoint record handle */
01210   UInt16                rec;                    /* record index */
01211   double                wpt_lat;                /* waypoint latitude */
01212   double                wpt_lon;                /* waypoint longitude */
01213   double                wpt_dst;                /* distance to waypoint */
01214   double                prox_dst;               /* wpt's proximity distance */
01215   Err                   err;                    /* error code */
01216   
01217   /* find active waypoint */
01218   err = DmFindRecordByID(gWaypointDB, gPrefs.act_wpt.waypointID,
01219     &rec);
01220         
01221   if (!err) {
01222     /* active waypoint found */
01223     waypointDBEntry = DmQueryRecord(gWaypointDB, rec);
01224     packed_waypoint =
01225       (packed_waypoint_t *)MemHandleLock(waypointDBEntry);
01226     UnpackWaypoint(&waypoint, packed_waypoint);
01227     wpt_lat = semi2deg(waypoint.posn.lat);
01228     wpt_lon = semi2deg(waypoint.posn.lon);
01229     prox_dst = (double)waypoint.dst;
01230     MemHandleUnlock(waypointDBEntry);
01231   
01232     /* get distance to active waypoint */
01233     wpt_dst = gc_dist_sphere(lat, lon, wpt_lat, wpt_lon) * calcR(lat);
01234     
01235     /* use default if waypoint has no proximity distance set */
01236     if (prox_dst == 0.0)
01237       prox_dst = APPROACH_DST;
01238     
01239     /* compare current distance with proximity distance */
01240     if (wpt_dst <= prox_dst) {
01241       return true;
01242     }
01243   }
01244   
01245   return false;
01246 }
01247 
01248 
01249 /****************************************************************************/
01250 /**
01251  * \brief       generate notification if Active Waypoint is within
01252  *              proximity distance
01253  *
01254  *              Depending on the user settings, audible and/or visible
01255  *              notification is triggered. In audible only mode, just one
01256  *              alarm sound is played. Otherwise an alert form is opened
01257  *              and has to be acknowledged by the user. After achnowledgement,
01258  *              the notification will not be repeated for this waypoint.
01259  *
01260  ****************************************************************************/
01261 void NotifyApproach(void)
01262 {
01263   static Boolean                alarm_ok = false;       /* flag: alarm done */
01264   static UInt32                 wpt_id_old = 0;         /* saved act. wpt. ID */
01265 
01266  if (gGPSData.valid && gPrefs.act_wpt.valid) {
01267 
01268     if (gPrefs.act_wpt.waypointID != wpt_id_old) {
01269       /* new active waypoint - reset approach alert */
01270       alarm_ok = false;
01271     }
01272 
01273     if ( CheckApproach(gGPSData.lat, gGPSData.lon) && !alarm_ok) {
01274       /*
01275        * Trigger approach notification, audible and/or visible.
01276        * The alert is generated once. To retrigger the detection, the
01277        * active waypoint ID has to change.
01278        */  
01279       if (gPrefs.approach_sound) {
01280         SndPlaySystemSound(sndAlarm);
01281       }
01282       if (gPrefs.approach_alert) {
01283         FrmGotoForm(ApproachForm);
01284       }
01285 
01286       alarm_ok = true;
01287     }
01288 
01289     /* save active waypoint ID for change detection */
01290     wpt_id_old = gPrefs.act_wpt.waypointID;
01291   }
01292 }
01293 
01294 
01295 /****************************************************************************/
01296 /**
01297  * \brief       Open a database.
01298  *
01299  *              If it doesn't exist, create it.
01300  * 
01301  * \param       dbP     Database reference ptr
01302  * \param       type    Type of the database
01303  * \param       creator Creator of the database
01304  * \param       mode    Open mode
01305  * \param       cardNo  Card number
01306  * \param       name    Database name
01307  * \param       created Flag: new database has been created (return value)
01308  *
01309  * \return      Error code of DmOpenDatabaseByTypeCreator() or
01310  *              DmCreateDatabase(), respectively.
01311  *              created -- Flag: new database has been created
01312  *                         (returned by reference)
01313  *****************************************************************************/
01314 Err OpenOrCreateDB(DmOpenRef *dbP, UInt32 type, UInt32 creator, 
01315   UInt16 mode, UInt16 cardNo, char *name, Boolean *created)
01316 {
01317   Err err = errNone;
01318   
01319   *created = false;
01320   *dbP = DmOpenDatabaseByTypeCreator(type, creator, mode);
01321   if (! *dbP)
01322   {
01323     err = DmGetLastErr();
01324     if (err == dmErrCantFind)
01325       err = DmCreateDatabase(cardNo, name, creator, type, false);
01326     if (err != errNone) 
01327       return err;
01328     *created = true;
01329     
01330     *dbP = DmOpenDatabaseByTypeCreator(type, creator, mode);
01331     if (! *dbP) 
01332       return DmGetLastErr();
01333   }
01334   return err;
01335 }
01336 
01337 
01338 /****************************************************************************/
01339 /**
01340  * \brief       Creates a Waypoint Database.
01341  *
01342  *              The Database contains the capitals of all states of the
01343  *              European Community (as of 03/2004).
01344  *              The waypoints were taken from http://wayhoo.com, which in turn
01345  *              uses GNS (http://gnswww.nima.mil/geonames/GNS/index.jsp).
01346  *
01347  *              Quoted from Wayhoo:
01348  *              Note: GNS coordinates have a low degree of precision,
01349  *                    latitude and longitude.
01350  *
01351  *              The Waypoint Identifiers (i.e. short names) are comprised of
01352  *              the ISO Country Code and the IATA (International Air
01353  *              Transport Association) Location ID.
01354  *              (see http://www.iata.org/codes/index.htm)
01355  *
01356  *              This is just an example after all.
01357  *
01358  *****************************************************************************/
01359 void InitializeWaypoints(void)
01360 {
01361   waypoint_t waypoints[] = {
01362     {"AT-VIE", {DEG2SEMI(48.20000), DEG2SEMI(16.36667)} , 0, 
01363       "Vienna, Austria (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01364     {"BE-BRU", {DEG2SEMI(50.83333), DEG2SEMI(4.33333)} , 0, 
01365       "Brussels, Belgium (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01366     {"DK-CPH", {DEG2SEMI(55.66667), DEG2SEMI(12.58333)} , 0, 
01367       "Copenhagen, Denmark (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01368     {"FI-HEL", {DEG2SEMI(60.17556), DEG2SEMI(24.93417)} , 0, 
01369       "Helsinki, Finland (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01370     {"FR-PAR", {DEG2SEMI(48.86667), DEG2SEMI(2.33333)} , 0, 
01371       "Paris, France (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01372     {"DE-BER", {DEG2SEMI(52.51667), DEG2SEMI(13.40000)} , 0, 
01373       "Berlin, Germany (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01374     {"GR-ATH", {DEG2SEMI(37.98333), DEG2SEMI(23.73333)} , 0, 
01375       "Athens, Greece (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01376     {"IE-DUB", {DEG2SEMI(53.33306), DEG2SEMI(-6.24889)} , 0, 
01377       "Dublin, Ireland (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01378     {"IT-ROM", {DEG2SEMI(41.90000), DEG2SEMI(12.48333)} , 0, 
01379       "Rome, Italy (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01380     {"LU-LUX", {DEG2SEMI(49.61167), DEG2SEMI(6.13000)} , 0, 
01381       "Luxembourg, Luxembourg (Capital)", 4000.0, sym_lrg_cty, dspl_smbl_only },
01382     {"NL-HAG", {DEG2SEMI(52.08333), DEG2SEMI(4.30000)} , 0, 
01383       "The Hague, Netherlands (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01384     {"PT-LIS", {DEG2SEMI(38.71667), DEG2SEMI(-9.13333)} , 0, 
01385       "Lisbon, Portugal (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01386     {"ES-MAD", {DEG2SEMI(40.40000), DEG2SEMI(-3.68333)} , 0, 
01387       "Madrid, Spain (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01388     {"SE-STO", {DEG2SEMI(59.33333), DEG2SEMI(18.05000)} , 0, 
01389       "Stockholm, Sweden (Capital)", 5000.0, sym_lrg_cty, dspl_smbl_only },
01390     {"GB-LON", {DEG2SEMI(51.50000), DEG2SEMI(-0.11667)} , 0, 
01391       "London, United Kingdom (Capital)", 10000.0, sym_lrg_cty, dspl_smbl_only }
01392   }; 
01393   
01394 //    {"BS", {DEG2SEMI(52.2692), DEG2SEMI(10.52111)} , 0, 
01395 //      "Braunschweig, Germany", 5000.0, sym_med_cty, dspl_smbl_only };
01396 //    {"DE-BWE", {DEG2SEMI(52.319168), DEG2SEMI(10.556167)} , 0, 
01397 //      "Airport Braunschweig, Germany ICAO:EDVE", 1000.0, sym_airport,
01398 //      dspl_smbl_only };
01399 
01400   UInt16  numWaypoints = sizeof(waypoints) / sizeof(waypoints[0]);
01401   UInt16  i;
01402     
01403   for (i = 0; i < numWaypoints; i++) {
01404     UInt16      index;
01405     MemHandle   h;
01406     
01407     index = DmFindSortPosition(gWaypointDB,
01408       &waypoints[i],
01409       0 /* newRecordInfo */,
01410       (DmComparF *)CompareWayptIdent /* DmComparF *compar */,
01411       0 /* other */);
01412     
01413     h = DmNewRecord(gWaypointDB, &index, 1);
01414     
01415     if (h) {
01416       DmReleaseRecord(gWaypointDB, index, false /* dirty */);
01417       PackWaypoint(&waypoints[i], index);
01418     } else {
01419       Die("Cannot create waypoint record (init)!");
01420     }
01421   }
01422 }

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