示例#1
0
static void CloseDatabase(AirspaceDBType *db) {

	LOGENTRY;

	if (db->external) {

		LOGTAG("Closing external");

		DBRecordFree(db->lat1Idx);
		DBRecordFree(db->lon1Idx);
		DBRecordFree(db->lat3Idx);
		DBRecordFree(db->lon3Idx);
		DBRecordFree(db->typeIdx);

		PFCloseFile(db->extDB);

	} else {

		LOGTAG("Closing internal");
		DBRecordFree(db->lat1Idx);
		DBRecordFree(db->lon1Idx);
		DBRecordFree(db->lat3Idx);
		DBRecordFree(db->lon3Idx);
		DBRecordFree(db->typeIdx);

		DBClose(db->intDB);

	}

	PFMemFree(db);

	LOGEXIT;

}
示例#2
0
static Boolean AsImportDB(PFFileRef f, const char *dbname, UInt32 dbType, void (*cb)(const char *)) {

	DmOpenRef db;
	UInt16 j;
	UInt16 numRecords;

	LOGENTRY;
	LOGSTR(dbname);
	LOGINT32(dbType);

	db = DBOpen(dbname, false, true);

	ModErrThrowIf(!db);

	LOGLINE;

	/*
	 * purge any existing records
	 *
	 */

	numRecords = DBGetNumRecords(db);
	LOGINT16(numRecords);
	if (numRecords) {

		(*cb)(StrPurgingDatabase);
		DBClose(db);
		DBDelete(dbname);

		db = DBOpen(dbname, false, true);

	}

	/*
	 * dimension new database.
	 *
	 * 5 index records
	 *
	 */

	LOGLINE;

	(*cb)(StrCreatingdatabaseStructure);
	for (j=0;j<lastIdxRec;j++) {

		UInt16 recnum = DBNewRecord;

		(void)DBRecordCreate(db, recnum, NULL, 1);

	}

	/*
	 * import records from file
	 *
	 */

	ErrTry {

		LOGINT16(numRecords);

		for (j=0;;j++) {

			AirspaceType *as;
			UInt16 recNum = j+lastIdxRec; // skip past db headers

			Int16 lat1, lon1, lat3, lon3;

			LOGTAG("Adding:");
			LOGINT16(j);

			as = ImportRecord(f, &lat1, &lon1, &lat3, &lon3, cb);

			if (as == NULL) {
				
				LOGTAG("End of file mark");
				break;

			}

			LOGINT16(PFMallocSize(as));

			/*
			 * add record to the database
			 *
			 */

			(void)DBRecordCreate(db, recNum, as, PFMallocSize(as));
			
			LOGTAG("Bounds:");
			LOGINT16(lat1);
			LOGINT16(lon1);
			LOGINT16(lat3);
			LOGINT16(lon3);

			/*
			 * store bounding coordinates and airspace type
			 *
			 */

			AddIntToRecord(db, lat1IdxRec, lat1);
			AddIntToRecord(db, lon1IdxRec, lon1);
			AddIntToRecord(db, lat3IdxRec, lat3);
			AddIntToRecord(db, lon3IdxRec, lon3);
			AddIntToRecord(db, typeIdxRec, as->type);

			PFMemFree(as);

		}

	} ErrCatch(errNo) {

		(*cb)(StrErrorDetectedPurgingDatabase);
		DBClose(db);
		DBDelete(dbname);

		errNo = 0;
		return false;

	} ErrEndCatch;
	
	DBClose(db);

	LOGEXIT;
	return true;

}
示例#3
0
static AirspaceDBType *OpenDatabase(char *intName) {

	AirspaceDBType *db = PFMalloc(sizeof(AirspaceDBType));
	char extName[64];

	ModErrThrowIf(!db);

	/*
	 * check for external database first
	 *
	 */

	StrPrintF(extName, "/PALM/Launcher/%s.pdb", intName);
	if ((db->extDB = PFOpenFile(extName, pfFileReadOnly))) {

		LOGTAG("External airspace");
		db->numRecords = DBFGetNumRecords(db->extDB) - lastIdxRec;

		if (db->numRecords > 0) {

			db->lat1Idx = DBFRecordGet(db->extDB, lat1IdxRec, false);
			db->lon1Idx = DBFRecordGet(db->extDB, lon1IdxRec, false);
			db->lat3Idx = DBFRecordGet(db->extDB, lat3IdxRec, false);
			db->lon3Idx = DBFRecordGet(db->extDB, lon3IdxRec, false);
			db->typeIdx = DBFRecordGet(db->extDB, typeIdxRec, false);

		} else {
			
			PFCloseFile(db->extDB);

		}

		db->external = true;

	}  else {

		/*
		 * check internal...
		 *
		 */

		LOGTAG("Internal airspace");
		db->external = false;
		db->intDB = DBOpen(intName, false, true);

		db->numRecords = DBGetNumRecords(db->intDB) - lastIdxRec;

		if (db->numRecords > 0) {
			
			db->lat1Idx = DBRecordGet(db->intDB, lat1IdxRec, false);
			db->lon1Idx = DBRecordGet(db->intDB, lon1IdxRec, false);
			db->lat3Idx = DBRecordGet(db->intDB, lat3IdxRec, false);
			db->lon3Idx = DBRecordGet(db->intDB, lon3IdxRec, false);
			db->typeIdx = DBRecordGet(db->intDB, typeIdxRec, false);

		} else {
			
			DBClose(db->intDB);

		}

	}

	LOGINT16(db->numRecords);

	if (db->numRecords < 1) {

		PFMemFree(db);
		db = NULL;

	}

	return db;

}
示例#4
0
static AirspaceType *ImportRecord(PFFileRef f, Int16 *lat1, Int16 *lon1, Int16 *lat3, Int16 *lon3,
		void (*cb)(const char *)) {

	char line[256], name[256];
	char *description = PFMalloc(4096);
	char *segStr = PFMalloc(2400);
	Int16 segCount;
	AirspaceType *as = PFMalloc(2400+2400*sizeof(LineSegmentType));
	void *segStart = PFMalloc(2400*sizeof(LineSegmentType));
	void *segPtr   = segStart;
	void *writePtr;
	double blat1, blon1, blat2, blon2;

	LOGENTRY;
	ModErrThrowIf(!description);
	ModErrThrowIf(!segStr);
	ModErrThrowIf(!as);
	ModErrThrowIf(!segStart);

	/*
	 * type & class:
	 *
	 * A-G = class A to G
	 *
	 * S[ADMPRTW]= Special Use (SUAS)
	 *
	 * W[LHB] = Airway, (L)ow level, (H)igh level or Both
	 *
	 * O= Other
	 *
	 */

	if (!PFReadLine(f,line)) {

		PFMemFree(as);
		PFMemFree(description);
		PFMemFree(segStart);
		PFMemFree(segStr);

		LOGEXIT;
		return NULL;

	}

	switch (line[0]) {

	case 'A': as->type = asTypeClassA; break;
	case 'B': as->type = asTypeClassB;break;
	case 'C': as->type = asTypeClassC;break; 
	case 'D': as->type = asTypeClassD;break;
	case 'E': as->type = asTypeClassE;break;
	case 'F': as->type = asTypeClassF;break;
	case 'G': as->type = asTypeClassG;break;

	case 'S':
		switch (line[1]) {

		case 'A': as->type = suasAlert;
			  break;
		case 'D': as->type = suasDanger;
			  break;
		case 'M': as->type = suasMoa;
			  break;
		case 'P': as->type = suasProhibited;
			  break;
		case 'R': as->type = suasRestricted;
			  break;
		case 'T': as->type = suasTra;
			  break;
		case 'W': as->type = suasWarning;
			  break;

		}
		as->type |= asTypeSUAS;
		break;

	case 'W':
		switch(line[1]) {

		case 'L': as->type = asTypeLowAirway;
			  break;

		case 'H': as->type = asTypeHighAirway;
			  break;

		case 'B': as->type = asTypeHighAirway | asTypeLowAirway;
			  break;

		default:ErrThrow(113);
			break;

		}
		break;

	case 'O':
		as->type = asTypeOther;
		break;

	default:
		ErrThrow(114);
		break;

	}

	LOGINT16(as->type);

	/*
	 * name
	 *
	 */

	PFReadLine(f, line);
	StrCopy(name, line);

	(*cb)(name);

	/*
	 * description
	 *
	 */

	*description = 0;
	while (line[0] != '-') {

		StrCat(description, line);
		StrCat(description, "\n");
		PFReadLine(f, line);
		LOGSTR(line);

	}

	/*
	 * frequency or RNP
	 *
	 */

	PFReadLine(f,line);

	if (as->type & asTypeAirway) {

		as->extra = StrAToI(line);

	} else {
		
		as->extra = (StrAToI(line)*256+StrAToI(&line[4]));

	}
	LOGINT16(as->extra);

	/*
	 * lower & upper altitude
	 * 
	 */

	PFReadLine(f,line);
	ImportAltitude(line, &as->lowerAltRef, &as->lowerAlt);

	PFReadLine(f,line);
	ImportAltitude(line, &as->upperAltRef, &as->upperAlt); 

	LOGINT16(as->lowerAlt);
	LOGINT16(as->upperAlt);
	
	/*
	 * boundary segments follow:
	 *
	 * L = Line:
	 *
	 * L<lat> <lon>
	 *
	 * A = Arc:
	 *
	 * A[LR]<lat2> <lon2> <lat3> <lon3> <lat1> <lon1>
	 *
	 * (L=left arc, R=right arc)
	 *
	 * (point 1 is centre, 2 and 3 are start and end points)
	 *
	 * C = Circle:
	 *
	 * C<lat> <lon> <radius>
	 *
	 * segStr is built and the bounding limits of the airspace (blat1 etc)
	 * are updated as the segments are read and processed
	 *
	 */

	blat1 = -PI/2;
	blon1 = -PI;
	blat2 = PI/2;
	blon2 = PI;

	segCount = 0;

	PFReadLine(f,line);

	while (line[0] != 'X') {

		const char *s = line+1;

		if (line[0] == 'L') {

			LineSegmentType l;
			double lat, lon;

			lat = StrToDouble(s);
			l.lat = DEG_TO_INT32(lat);

			SKIP_FIELD(s);
			lon = 0-StrToDouble(s);
			l.lon = DEG_TO_INT32(lon);

			//LOGINT32(l.lat); LOGINT32(l.lon);

			segStr[segCount] = 'l';
			*(LineSegmentType*)segPtr = l;
			segPtr += sizeof(LineSegmentType);

			blat1 = MAX(blat1, DEG_TO_RAD(lat));
			blon1 = MAX(blon1, DEG_TO_RAD(lon));
			blat2 = MIN(blat2, DEG_TO_RAD(lat));
			blon2 = MIN(blon2, DEG_TO_RAD(lon));

		} else if (line[0] == 'A') {

			double lat1, lon1;
			double lat2, lon2;
			double lat3, lon3;
			double radius,bearing;

			ArcSegmentType ar;

			s+=1;

			/*
			 * end points
			 *
			 */

			lat2 = DEG_TO_RAD(StrToDouble(s));
			SKIP_FIELD(s);
			lon2 = 0-DEG_TO_RAD(StrToDouble(s));
			SKIP_FIELD(s);
			lat3 = DEG_TO_RAD(StrToDouble(s));
			SKIP_FIELD(s);
			lon3 = 0-DEG_TO_RAD(StrToDouble(s));

			/*
			 * centre
			 *
			 */
			
			SKIP_FIELD(s);
			lat1 = DEG_TO_RAD(StrToDouble(s));
			SKIP_FIELD(s);
			lon1 = 0-DEG_TO_RAD(StrToDouble(s));

			ar.lat = RAD_TO_INT32(lat1);
			ar.lon = RAD_TO_INT32(lon1);

			/*
			 * note to self:
			 *
			 * Because 0 < bearing < 2*PI (check AvCalcs),
			 * RAD_TO_INT16(bearing) can return under/overflow Int16 but
			 * luckily it doesn't matter - only under PalmOS though! Under
			 * CygWin it definetely needs handling.
			 *
			 * During the porting process, this should be addressed
			 *
			 */

			bearing = AvCalcGreatCircleCourse(lat1, lon1, lat2, lon2, &radius);
			ar.radius = RAD_TO_INT32(radius); 
			ar.start  = RAD_TO_INT16(bearing); 
			bearing = AvCalcGreatCircleCourse(lat1, lon1, lat3, lon3, &radius); 
			ar.end    = RAD_TO_INT16(bearing);

			if (line[1] == 'L') ar.radius = -ar.radius;

			//LOGINT32(ar.radius);
			//LOGINT16(ar.start);
			//LOGINT16(ar.end);

			segStr[segCount] = 'a';
			*(ArcSegmentType*)segPtr = ar;
			segPtr += sizeof(ArcSegmentType);

			/*
			 * assume arc is a complete circle, and calculate
			 * bounding box accordingly
			 *
			 * latitude limits are easy - just add the
			 * radian-radius, and limit the max to +-90 degrees
			 *
			 */

			blat1 = MAX(blat1, MIN(PI/2, lat1+radius));
			blat2 = MIN(blat2, MAX(-PI/2,lat1-radius));

			/*
			 * longitude is more complicated, as it needs to wrap
			 * around.
			 *
			 * scale the radius according to our latitude
			 *
			 * remember west is +ve!!!
			 *
			 * Wrap around at 180deg W/E
			 *
			 */

			radius /= cos(lat1);

			lon1 += radius;
			if (lon1 > PI) lon1 -= 2*PI;
			blon1 = MAX(blon1, lon1);
			blon2 = MIN(blon2, lon1);

			lon1 -= 2*radius;
			if (lon1 < -PI) lon1 += 2*PI;
			blon1 = MAX(blon1, lon1);
			blon2 = MIN(blon2, lon1);

		} else if (line[0] == 'C') {

			double lat1, lon1;
			double radius;

			ArcSegmentType ar;

			/*
			 * centre
			 *
			 */
			
			lat1 = DEG_TO_RAD(StrToDouble(s));
			SKIP_FIELD(s);
			lon1 = 0-DEG_TO_RAD(StrToDouble(s));

			ar.lat = RAD_TO_INT32(lat1);
			ar.lon = RAD_TO_INT32(lon1);

			/*
			 * radius in nm
			 *
			 */

			SKIP_FIELD(s);
			radius = NM_TO_RAD(StrToDouble(s));
			ar.radius = RAD_TO_INT32(radius);
			ar.start  = 0;
			ar.end    = 0;

			//LOGINT32(ar.lat);LOGINT32(ar.lon);
			//LOGINT32(ar.radius);

			segStr[segCount] = 'a';
			*(ArcSegmentType*)segPtr = ar;
			segPtr += sizeof(ArcSegmentType);

			/*
			 * latitude limits are easy - just add the
			 * radian-radius, and limit the max to +-90 degrees
			 *
			 */

			blat1 = MAX(blat1, MIN(PI/2, lat1+radius));
			blat2 = MIN(blat2, MAX(-PI/2,lat1-radius));

			/*
			 * longitude is more complicated, as it needs to wrap
			 * around.
			 *
			 * scale the radius according to our latitude
			 *
			 * remember west is +ve!!!
			 *
			 * Wrap around at 180deg W/E
			 *
			 */

			radius /= cos(lat1);

			lon1 += radius;
			if (lon1 > PI) lon1 -= 2*PI;
			blon1 = MAX(blon1, lon1);
			blon2 = MIN(blon2, lon1);

			lon1 -= 2*radius;
			if (lon1 < -PI) lon1 += 2*PI;
			blon1 = MAX(blon1, lon1);
			blon2 = MIN(blon2, lon1);

		}

		segCount++;
		PFReadLine(f,line);

	}
	segStr[segCount] = 0;
	
	LOGINT16(segPtr - segStart);

	/*
	 * adjust length of strings so that the segment records
	 * start on an even byte boundary
	 *
	 */

	if ( (segCount+1 + StrLen(description) + 1) & 1 ) {

		LOGTAG("Adjusting length");
		StrCat(description,"\n");

	}
	
	/*
	 * add the segment string, name, auth and segment records to the
	 * airspace record
	 *
	 */

	LOGLINE;

	writePtr = (void*)&as->segmentCode;
	PFMemMove(writePtr, segStr, segCount+1);
	writePtr += segCount+1;
	PFMemMove(writePtr, description, StrLen(description)+1);
	writePtr += StrLen(description)+1;

	PFMemMove(writePtr, segStart, segPtr - segStart);
	writePtr += segPtr - segStart;

	LOGSTR(GetStringFromList(as->segmentCode,1));

	PFMallocResize(as, writePtr-(void*)as);

	LOGINT16(PFMallocSize(as));


	/*
	 * adjust the longitude limits if the span is > 180 degrees by
	 * swapping lon1 and lon2 around
	 *
	 */

	if (fabs(blon1 - blon2) > PI) {

		double tmp = blon1;

		blon1 = blon2;
		blon2 = tmp;

	}

	*lat1 = RAD_TO_INT16(blat1);
	*lon1 = RAD_TO_INT16(blon1);
	*lat3 = RAD_TO_INT16(blat2);
	*lon3 = RAD_TO_INT16(blon2);
	 
	PFMemFree(description);
	PFMemFree(segStart);
	PFMemFree(segStr);

	LOGEXIT;
	return as;

}
示例#5
0
AutoPtr< ArrayOf<String> > NativeDaemonEvent::UnescapeArgs(
    /* [in] */ const String& rawEvent)
{
    Boolean DEBUG_ROUTINE = FALSE;
    String LOGTAG("unescapeArgs");
    List<String> parsed;
    Int32 length = rawEvent.GetLength();
    Int32 current = 0;
    Int32 wordEnd = -1;
    Boolean quoted = FALSE;

//    if (DEBUG_ROUTINE) Slog.e(LOGTAG, "parsing '" + rawEvent + "'");
    if (rawEvent.GetChar(current) == '\"') {
        quoted = TRUE;
        current++;
    }
    while (current < length) {
        // find the end of the word
        char terminator = quoted ? '\"' : ' ';
        wordEnd = current;
        while (wordEnd < length && rawEvent.GetChar(wordEnd) != terminator) {
            if (rawEvent.GetChar(wordEnd) == '\\') {
                // skip the escaped char
                ++wordEnd;
            }
            ++wordEnd;
        }
        if (wordEnd > length) wordEnd = length;
        String word = rawEvent.Substring(current, wordEnd);
        current += word.GetLength();
        if (!quoted) {
            word = word.Trim();
        }
        else {
            current++;  // skip the trailing quote
        }
        // unescape stuff within the word
        String w;
        StringUtils::ReplaceAll(word, String("\\\\"), String("\\"), &w);
        StringUtils::ReplaceAll(w, String("\\\""), String("\""), &word);

//        if (DEBUG_ROUTINE) Slog.e(LOGTAG, "found '" + word + "'");
        parsed.PushBack(word);

        // find the beginning of the next word - either of these options
        Int32 nextSpace = rawEvent.IndexOf(' ', current);
        Int32 nextQuote = rawEvent.IndexOf(" \"", current);
        if (DEBUG_ROUTINE) {
//            Slog.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote);
        }
        if (nextQuote > -1 && nextQuote <= nextSpace) {
            quoted = TRUE;
            current = nextQuote + 2;
        }
        else {
            quoted = FALSE;
            if (nextSpace > -1) {
                current = nextSpace + 1;
            }
        } // else we just start the next word after the current and read til the end
        if (DEBUG_ROUTINE) {
//            Slog.e(LOGTAG, "next loop - current=" + current +
//                    ", length=" + length + ", quoted=" + quoted);
        }
    }
    AutoPtr< ArrayOf<String> > parsedArray = ArrayOf<String>::Alloc(parsed.GetSize());
    List<String>::Iterator it;
    Int32 i;
    for (it = parsed.Begin(), i = 0; it != parsed.End(); ++it, i++) {
        (*parsedArray)[i] = *it;
    }
    return parsedArray;
}
void AlarmSetCondition(MessageDialogDataType *md, AlarmLevelType level) {

	Int16 j;

	/*
	 * check existing alarms 
	 *
	 */

	LOGENTRY;

	for (j=0; j< numAlarms; j++) {

		if (StrCompare(md->message, alarm[j].data->message) == 0) {

			/*
			 * found the same alarm, check if it's being cleared or if we should
			 * increase the alarm level 
			 *
			 */

			LOGTAG("Found existing alarm");
			LOGSTR(alarm[j].data->message);

			if (level == alarmOff) {

				/*
				 * clear the alarm
				 *
				 */

				ClearAlarm(j);
				MessageDialogDataFree(md);
				LOGEXIT;
				return;

			}

			/*
			 * increase alarm level?
			 *
			 */

			if (alarm[j].level < level) {
				
				alarm[j].level = level;
				alarm[j].time = PFGetSeconds();
				alarm[j].returnedCounter = MAX_RETURNS;

			}

			MessageDialogDataFree(md);
			LOGEXIT;
			return;

		}

	}

	/*
	 * the code above should have removed the existing alarm condition 
	 * if level == alarmOff, so just return from here
	 *
	 */

	if (level == alarmOff) {

		MessageDialogDataFree(md);
		LOGEXIT;
		return;

	}

	/*
	 * new alarm
	 *
	 */

	ModErrThrowIf(numAlarms == MAX_ALARMS);
	alarm[numAlarms].level = level;
	alarm[numAlarms].data  = md;
	alarm[numAlarms].ack = false;
	alarm[numAlarms].time = PFGetSeconds();
	alarm[numAlarms].returnedCounter = MAX_RETURNS;

	numAlarms++;

	LOGEXIT;

}
/*
 * function : ScanForWaypoints
 *
 * Scans for proximity waypoints. maxTicks specifies how long we're allowed
 * to run for. If stopOnEvent is true then an event in the PalmOS event
 * queue can interrupt the scan.
 *
 * Returns true if the scan reached the end of its cycle
 *
 */
static Boolean ScanForWaypoints(UInt16 maxTicks, Boolean stopOnEvent) {

	UInt32                startTime = PFGetTicks();
	Waypoint             *wp;
	double                wpRange;
	double                wpBearing, wpBearingFrom;
	double         		maxRange;
	UInt16                j;
	UInt16                runwayIcon = 0;
	static UInt32         lastScanTime;
	Int16                 numScanned = 0;
	ShortWaypointType     *swp;
	
	/*
	 * scan state machine controls what we should do:
	 *
	 * scanning - obvious really!
	 *
	 * waiting  - waiting for 8 seconds between scans
	 *
	 * starting - ready to start a new scan
	 *
	 */

	LOGENTRY;

	if (scanState == waiting) {

		if (PFTimerHasExpired(lastScanTime, PFTicksPerSecond()*8)) {

			scanState = starting;

		} 

	}

	if (scanState == starting) {

		newProxList->numWaypoints = 0;

		LOGTAG("Scan starting");

		search = WDMInitProxScan(WPDataset, GPS.posn.lat32,
				GPS.posn.lon32, FMDS.noObstacles, searchMask);

		/*
		 * No waypoints to search
		 *
		 */

		if (!search) {
			
			scanState = waiting;
			lastScanTime=PFGetTicks();
			LOGEXIT;
			return true;

		}

		scanState = scanning;

	}
		
	if (scanState != scanning) {
		
		LOGEXIT;
		return false;

	}

	/*
	 * determine how far out we should look from current position. If all
	 * of the prox lists are full then the max we should look is not beyond
	 * the furthest waypoint, otherwise we default to 3000 nm.
	 *
	 */

	if (newProxList->numWaypoints == MAX_PROXWAYPOINTS) {

		maxRange = newProxList->waypoints[MAX_PROXWAYPOINTS-1].range;

	} else {
		
		if (searchString[0] == 0) {

			maxRange = 3000.0/NM_PER_RADIAN;

		} else {

			/*
			 * search string specified - search entire database
			 *
			 */

			maxRange = 0.0;

		}

	}

	do {

		//LOGINT16((Int16) (maxRange*NM_PER_RADIAN));
		//LOGINT32(RAD_TO_INT32(maxRange));

		swp = WDMGetProxWaypoint(search, RAD_TO_INT32(maxRange));

		if (swp == NULL) {

			/*
			 * end of scanning cycle
			 *
			 */

			LOGTAG("EOScan");
			LOGINT16(numScanned);

			WDMFreeSearch(search);
			search = NULL;

			if (newProxList == &proxList) {

				newProxList = PFMalloc(sizeof(*newProxList));

			} else {

				PFMemMove(&proxList, newProxList, sizeof(*newProxList));

			}

			scanState = waiting;
			lastScanTime=PFGetTicks();

			LOGEXIT;
			return true;

		}

		numScanned++;

		//LOGTAG("Considering:");
		//LOGSTR(wp->ident);

		/*
		 * discard based on ident-search
		 *
		 */

		if (searchString[0] && identOnly) {

			char ident[6];

			StrNCopy(ident, swp->extra, sizeof(ident)-1);
			ident[sizeof(ident)-1] = 0;

			if (StrNCaselessCompare(ident, searchString, StrLen(searchString)) != 0) {

				continue;

			}

		}

		wp = WDMGetWaypoint(WPDataset, swp->wpId);

		/*
		 * discard based on search string
		 *
		 */

		if (searchString[0]) {
			
			char s[20], d[100];
			char *subStr;

			StrToLower(d, wp->ident);
			StrToLower(s, searchString);

			subStr = StrStr(d,s);
/*
			if (identOnly && subStr != d) {

				PFMemFree((void*)wp);
				continue;

			}
			*/

			if (!subStr) {

				StrToLower(d, GetStringFromList(wp->ident,1));

				if (!StrStr(d,s)) {

					PFMemFree(wp);
					continue;

				}

			}

		}

		/*
		 * runway surface and dimension checks - discard any airfield
		 * that doesn't meet these criteria
		 *
		 * NB We don't discard a waypoint based on runway dimensions
		 * if a search string is specified.
		 *
		 */

		if ( WDMGetWaypointType(wp) & wpAllAirfields ) {

			CpRunwayInfoType *runways;
			UInt16            numRunways;
			Boolean           found = false;

			runways = CpGetRunwayInfo(GetStringFromList(wp->ident,2),&numRunways);
			if (runways) {

				UInt16 k;

				/*
				 * there are 8 icons for the runways, to represent 180
				 * degrees, which gives 22.5 degrees of coverage per
				 * icon. Quadrupling everything allows us to use whole
				 * numbers for the calculation.
				 *
				 */

				runwayIcon = ((runways[0].heading*10 + 5)*4 + 45) / 90;
				WRAPMAX(runwayIcon, 7);

				for (k=0;k<numRunways && runways[k].length >= Preferences.runwayLength;k++) {

					/*
					 * if this runway's width and surface are appropriate, then
					 * we'll use it's heading to determine which icon to
					 * display
					 *
					 */

					if (runways[k].width >= Preferences.runwayWidth &&
					  ( Preferences.runwaySurface == surfEither ||
					  ((Preferences.runwaySurface == surfHard && runways[k].hardSurface) || 
					  (Preferences.runwaySurface == surfGrass && !runways[k].hardSurface)))) {

						runwayIcon = ((runways[0].heading*10 + 5)*4 + 45) / 90;
						WRAPMAX(runwayIcon, 7);
						found = true;
						break;

					}

				}

				PFMemFree(runways);

			} else {

				runwayIcon = 8;

				if (Preferences.runwayWidth == 0 && Preferences.runwayLength == 0) found = true;

			}

			 /*
			  * NB We don't discard a waypoint based on runway dimensions if a
			  * search string is specified.
			  *
			  */
		
			if (!found && !searchString[0] && displayFilter != all) { 

				/*
				 * discard 
				 *
				 */

				PFMemFree(wp);
				continue;

			}

		}

		wpBearingFrom = AvCalcGreatCircleCourse(wp->latitude, wp->longitude,
				GPS.posn.latitude, GPS.posn.longitude, &wpRange); 

		wpBearing = AvCalcGreatCircleCourse(GPS.posn.latitude, GPS.posn.longitude,
				wp->latitude, wp->longitude,
				&wpRange);

		/*
		 * if we're using magnetic headings, convert the bearing
		 * to use local magnetic variation
		 *
		 */

		if (Preferences.useMagnetic) {

			wpBearing += DEG_TO_RAD((double)GPS.posn.magVarn);
			wpBearingFrom += wp->magVar;

			WRAPMAX(wpBearing,2*PI);
			WRAPMAX(wpBearingFrom,2*PI);

		}

		/*
		 * look for the insertion position if necessary
		 *
		 */

		if (newProxList->numWaypoints > 0) {

			/*
			 * it's a good idea to look backwards through this
			 * list, as waypoints are most likely to be added
			 * at the end
			 *
			 */

			for (j=newProxList->numWaypoints;j>0 && wpRange < newProxList->waypoints[j-1].range;j--);
		
			/*
			 * if this triggers then we haven't found a place to
			 * insert the waypoint - its range is beyond that of
			 * the last waypoint in the list
			 *
			 */

			if(j==newProxList->numWaypoints &&
				newProxList->numWaypoints==MAX_PROXWAYPOINTS) {

				PFMemFree(wp);
				continue;

			}

		} else {

			j = 0;

		}

		/*
		 * j is pointing to the insertion position 
		 *
		 * Don't bother shuffling other records if we're adding to the
		 * end of the list
		 *
		 */

		if (j<newProxList->numWaypoints) {

			/*
			 * move the waypoints down the list , set the change
			 * flag to mark them as having been updated.
			 *
			 */

			PFMemMove(&newProxList->waypoints[j+1], &newProxList->waypoints[j], 
					sizeof(ProxWaypointType)*(MAX_PROXWAYPOINTS-1-j));

		} 

		LOGTAG("Adding:");
		LOGSTR(wp->ident);
		newProxList->waypoints[j].id=swp->wpId;
		newProxList->waypoints[j].type=WDMGetWaypointType(wp);
		newProxList->waypoints[j].range=wpRange;
		newProxList->waypoints[j].bearing=(Int16) round(RAD_TO_DEG(wpBearing));
		newProxList->waypoints[j].bearingFrom=(Int16) round(RAD_TO_DEG(wpBearingFrom));
		newProxList->waypoints[j].runwayIcon = runwayIcon;
		StrCopy(newProxList->waypoints[j].ident,wp->ident);
		StrNCopy(newProxList->waypoints[j].name, GetStringFromList(wp->ident,1), MAX_NAMECHARS-1);
		newProxList->waypoints[j].name[MAX_NAMECHARS-1] = 0;

		if (newProxList->numWaypoints<MAX_PROXWAYPOINTS) {

			/*
			 * we haven't filled the list, so this waypoint *must*
			 * be a new entry in the list.
			 *
			 */

			newProxList->numWaypoints++;

		}
		
		PFMemFree(wp);

	} while (!(stopOnEvent && PFEventAvailable()) && !PFTimerHasExpired(startTime, maxTicks));

	LOGINT16(numScanned);

	LOGEXIT;

	return false;

}
/* 
 * function : DiversionFormHandleEvent
 *
 * Handles all events directed at the form.
 *
 * Returns true if the event is handled
 */
Boolean DiversionFormHandleEvent(EventPtr event)
{
	Boolean handled = false;
	char *alphaInput;

	switch (PFEventGetType(event)) 
	{
	case frmOpenEvent:
		DiversionFormInit();
		GUIFormResize(false, false);
		UpdateDisplay();

		handled = true;
		break;
			
	case winDisplayChangedEvent:

		if (GUIFormResize(false, false)) UpdateDisplay();
		handled = true;
		break;
		

	case evtGPSFix:
	case evtGPSFixLost:
	case evtGPSPositionUpdate:
	case nilEvent:

		/*
		 * turn scanning on/off according to state of GPS
		 *
		 */

		if (GPSState) {

			if ( (scanState != disabled && GPS.sat.fixType < 2) ||
				(scanState == disabled && GPS.sat.fixType > 1)) {

				ResetScan();
				if (!GUIMenuIsDisplayed()) UpdateDisplay();

			} else if (GUIFieldIsDirty(DvSearchStr)) {
				
				LOGTAG("Dirty field");
				GUIFieldClean(DvSearchStr);

				ResetScan();
				if (!GUIMenuIsDisplayed()) UpdateDisplay();

			} else if (scanState != disabled) {

				/*
				 * update the display if the scan is completed or while
				 * we're still searching
				 *
				 */

//				if (ScanForWaypoints(PFTicksPerSecond()*3/4,true) || newProxList == &proxList)

				(void)ScanForWaypoints(PFTicksPerSecond()*3/4,true);
				if (!GUIMenuIsDisplayed()) UpdateDisplay();

			}

		} else {

			/*
			 * if (FpIsBlank(FlightPlan)) {
			 *
			 * GUIObjectHide( MapPanToWaypointButton);
			 *
			 * }
			 *
			 * No GPS on, we're using our reference position
			 *
			 */

			if (ScanForWaypoints(PFTicksPerSecond()*3/4,true) || newProxList == &proxList)

				if (!GUIMenuIsDisplayed()) UpdateDisplay();


		}

		handled = true;
		break;

	case keyDownEvent:
		handled = HandleKeyEvent(event);
		break;

	case menuEvent:
		
		switch (PFEventGetMenuID(event)) {

		case MnDivertEmergency:
			GUIFormGoto(MapForm);
			handled = true;
			break;

		case MnInformation:

			if (selectedWaypointID != UNSELECTED) {

				/*
				 * waypoint is locked here, but will be unlocked by
				 * the WPInfoDialog
				 *
				 */

				WPInfoSetWaypointInfo(selectedWaypointID);
				GUIFormPopup(WPInfoDialog);

			}

			handled = true;
			break;

		}

		break;

	case ctlSelectEvent:
		handled = HandleCtlSelectEvent(event);
		break;

	case sclEnterEvent:
	case sclRepeatEvent:
	case sclExitEvent:
		handled = true;
		break;

	case penDownEvent:
		if (PFScreenPointInRectangle(PFEventGetX(event)*2, PFEventGetY(event)*2,
					&proxDisplayArea)) {
			handled = HandleProxSelectEvent(event);
		} 
		break;

	case fldEnterEvent:
		AlphaPadDialogInit(GUIFieldGetText(DvSearchStr));
		GUIFormPopup(AlphaPadDialog);
		handled = true;
		break;
		
	case evtAlphaInput:
		alphaInput = AlphaPadGetInput();
		GUIFieldSetText(DvSearchStr, alphaInput, true);
		PFMemFree(alphaInput);

		ResetScan();
		UpdateDisplay();
		handled = true;
		break;

	case frmCloseEvent:
		DiversionFormDeInit();
		handled = false;
		break;

	case evtWaypointInfoReq:
		
		/*
		 * this is sent by the command popup dialog
		 *
		 */


	default:
		break;
	}	
	return handled;
}