]> git.mxchange.org Git - flightgear.git/blobdiff - src/ATCDCL/commlist.cxx
Merge branch 'jd/atis' into next
[flightgear.git] / src / ATCDCL / commlist.cxx
index 140b3f2da0f487e9b589cbd491b39479ef41631d..baed76f373bea946e0e8d81858a2699dcf3dcd1a 100644 (file)
 #  include <config.h>
 #endif
 
+#include "commlist.hxx"
+
 #include <simgear/debug/logstream.hxx>
+#include <simgear/misc/sg_path.hxx>
 #include <simgear/misc/sgstream.hxx>
 #include <simgear/math/sg_geodesy.hxx>
 #include <simgear/math/sg_random.h>
 #include <simgear/bucket/newbucket.hxx>
 #include <Airports/simple.hxx>
 
-#include "commlist.hxx"
 #include "ATCutils.hxx"
 
 
@@ -40,6 +42,7 @@ FGCommList *current_commlist;
 
 // Constructor
 FGCommList::FGCommList( void ) {
+      sg_srandom_time();
 }
 
 
@@ -51,23 +54,23 @@ FGCommList::~FGCommList( void ) {
 // load the navaids and build the map
 bool FGCommList::init( const SGPath& path ) {
 
-       SGPath temp = path;
+    SGPath temp = path;
     commlist_freq.erase(commlist_freq.begin(), commlist_freq.end());
-       commlist_bck.erase(commlist_bck.begin(), commlist_bck.end());
+    commlist_bck.erase(commlist_bck.begin(), commlist_bck.end());
     temp.append( "ATC/default.atis" );
-       LoadComms(temp);
-       temp = path;
-       temp.append( "ATC/default.tower" );
-       LoadComms(temp);
-       temp = path;
-       temp.append( "ATC/default.ground" );
-       LoadComms(temp);
-       temp = path;
-       temp.append( "ATC/default.approach" );
-       LoadComms(temp);
-       return true;
+    LoadComms(temp);
+    temp = path;
+    temp.append( "ATC/default.tower" );
+    LoadComms(temp);
+    temp = path;
+    temp.append( "ATC/default.ground" );
+    LoadComms(temp);
+    temp = path;
+    temp.append( "ATC/default.approach" );
+    LoadComms(temp);
+    return true;
 }
-       
+    
 
 bool FGCommList::LoadComms(const SGPath& path) {
 
@@ -76,34 +79,34 @@ bool FGCommList::LoadComms(const SGPath& path) {
         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
         exit(-1);
     }
-       
+    
     // read in each line of the file
     fin >> skipcomment;
 
     while ( !fin.eof() ) {
         ATCData a;
-               fin >> a;
-               if(a.type == INVALID) {
-                       SG_LOG(SG_GENERAL, SG_DEBUG, "WARNING - INVALID type found in " << path.str() << '\n');
-               } else {                
-                       // Push all stations onto frequency map
-                       commlist_freq[a.freq].push_back(a);
-                       
-                       // Push non-atis stations onto bucket map as well
-                       // In fact, push all stations onto bucket map for now so FGATCMgr::GetFrequency() works.
-                       //if(a.type != ATIS) {
-                               // get bucket number
-                               SGBucket bucket(a.lon, a.lat);
-                               int bucknum = bucket.gen_index();
-                               commlist_bck[bucknum].push_back(a);
-                       //}
-               }
-               
-               fin >> skipcomment;
-       }
-       
-       fin.close();
-       return true;    
+        fin >> a;
+        if(a.type == INVALID) {
+            SG_LOG(SG_GENERAL, SG_DEBUG, "WARNING - INVALID type found in " << path.str() << '\n');
+        } else {        
+            // Push all stations onto frequency map
+            commlist_freq[a.freq].push_back(a);
+            
+            // Push non-atis stations onto bucket map as well
+            // In fact, push all stations onto bucket map for now so FGATCMgr::GetFrequency() works.
+            //if(a.type != ATIS and/or AWOS?) {
+                // get bucket number
+                SGBucket bucket(a.geod);
+                int bucknum = bucket.gen_index();
+                commlist_bck[bucknum].push_back(a);
+            //}
+        }
+        
+        fin >> skipcomment;
+    }
+    
+    fin.close();
+    return true;    
 }
 
 
@@ -111,98 +114,89 @@ bool FGCommList::LoadComms(const SGPath& path) {
 // degrees, elev is in meters
 // If no atc_type is specified, it returns true if any non-invalid type is found
 // If atc_type is specifed, returns true only if the specified type is found
-bool FGCommList::FindByFreq( double lon, double lat, double elev, double freq,
+bool FGCommList::FindByFreq(const SGGeod& aPos, double freq,
                                                ATCData* ad, atc_type tp )
 {
-       // HACK - if freq > 1000 assume it's in KHz, otherwise assume MHz.
-       // A bit ugly but it works for now!!!!
-       comm_list_type stations;
-       if(freq > 1000.0) {
-               stations = commlist_freq[(int)freq];
-       } else {
-               stations = commlist_freq[(int)(freq*100.0 + 0.5)];
-       }
-       comm_list_iterator current = stations.begin();
-       comm_list_iterator last = stations.end();
-       
-       // double az1, az2, s;
-       SGVec3d aircraft = SGVec3d::fromGeod(SGGeod::fromDegM(lon, lat, elev));
-       const double orig_max_d = 1e100; 
-       double max_d = orig_max_d;
-       // TODO - at the moment this loop returns the first match found in range
-       // We want to return the closest match in the event of a frequency conflict
-       for ( ; current != last ; ++current ) {
-               //cout << "testing " << current->get_ident() << endl;
-                SGVec3d station(current->x, current->y, current->z);
-               //cout << "aircraft = " << aircraft << endl;
-               //cout << "station = " << station << endl;
-               
-               double d = distSqr(aircraft, station);
-               
-               //cout << "  dist = " << sqrt(d)
-               //     << "  range = " << current->range * SG_NM_TO_METER << endl;
-               
-               // TODO - match up to twice the published range so we can model
-               // reduced signal strength
-               // NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt.
-               if ( d < (current->range * SG_NM_TO_METER 
-                    * current->range * SG_NM_TO_METER ) ) {
-                       //cout << "matched = " << current->ident << endl;
-                       if((tp == INVALID) || (tp == (*current).type)) {
-                               if(d < max_d) {
-                                       max_d = d;
-                                       *ad = *current;
-                               }
-                       }
-               }
-       }
-       
-       if(max_d < orig_max_d) {
-               return true;
-       } else {
-               return false;
-       }
+    comm_list_type stations;
+    stations = commlist_freq[kHz10(freq)];
+    comm_list_iterator current = stations.begin();
+    comm_list_iterator last = stations.end();
+    
+    // double az1, az2, s;
+    SGVec3d aircraft = SGVec3d::fromGeod(aPos);
+    const double orig_max_d = 1e100; 
+    double max_d = orig_max_d;
+    double d;
+    // TODO - at the moment this loop returns the first match found in range
+    // We want to return the closest match in the event of a frequency conflict
+    for ( ; current != last ; ++current ) {
+        d = distSqr(aircraft, current->cart);
+        
+        //cout << "  dist = " << sqrt(d)
+        //     << "  range = " << current->range * SG_NM_TO_METER << endl;
+        
+        // TODO - match up to twice the published range so we can model
+        // reduced signal strength
+        // NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt.
+        if ( d < (current->range * SG_NM_TO_METER 
+             * current->range * SG_NM_TO_METER ) ) {
+            //cout << "matched = " << current->ident << endl;
+            if((tp == INVALID) || (tp == (*current).type)) {
+                if(d < max_d) {
+                    max_d = d;
+                    *ad = *current;
+                }
+            }
+        }
+    }
+    
+    if(max_d < orig_max_d) {
+        return true;
+    } else {
+        return false;
+    }
 }
 
-int FGCommList::FindByPos(double lon, double lat, double elev, double range, comm_list_type* stations, atc_type tp)
+int FGCommList::FindByPos(const SGGeod& aPos, double range, comm_list_type* stations, atc_type tp)
 {
-       // number of relevant stations found within range
-       int found = 0;
-       stations->erase(stations->begin(), stations->end());
-       
-       // get bucket number for plane position
-       SGBucket buck(lon, lat);
-
-       // get neigboring buckets
-       int bx = (int)( range*SG_NM_TO_METER / buck.get_width_m() / 2);
-       int by = (int)( range*SG_NM_TO_METER / buck.get_height_m() / 2 );
-       
-       // loop over bucket range 
-       for ( int i=-bx; i<=bx; i++) {
-               for ( int j=-by; j<=by; j++) {
-                       buck = sgBucketOffset(lon, lat, i, j);
-                       long int bucket = buck.gen_index();
-                       comm_list_type Fstations = commlist_bck[bucket];
-                       comm_list_iterator current = Fstations.begin();
-                       comm_list_iterator last = Fstations.end();
-                       
-                       // double az1, az2, s;
-                        SGVec3d aircraft = SGVec3d::fromGeod(SGGeod::fromDegM(lon, lat, elev));
-                       for(; current != last; ++current) {
-                               if((current->type == tp) || (tp == INVALID)) {
-                                        SGVec3d station(current->x, current->y, current->z);
-                                       double d = distSqr(aircraft, station);
-                                       // NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt.
-                                       if ( d < (current->range * SG_NM_TO_METER
-                                            * current->range * SG_NM_TO_METER ) ) {
-                                               stations->push_back(*current);
-                                               ++found;
-                                       }
-                               }
-                       }
-               }
-       }
-       return found;
+     // number of relevant stations found within range
+     int found = 0;
+     stations->erase(stations->begin(), stations->end());
+     
+     // get bucket number for plane position
+     SGBucket buck(aPos);
+     // get neigboring buckets
+     int bx = (int)( range*SG_NM_TO_METER / buck.get_width_m() / 2);
+     int by = (int)( range*SG_NM_TO_METER / buck.get_height_m() / 2 );
+     
+     // loop over bucket range 
+     for ( int i=-bx; i<=bx; i++) {
+         for ( int j=-by; j<=by; j++) {
+             buck = sgBucketOffset(aPos.getLongitudeDeg(), aPos.getLatitudeDeg(), i, j);
+             long int bucket = buck.gen_index();
+             comm_list_type Fstations = commlist_bck[bucket];
+             comm_list_iterator current = Fstations.begin();
+             comm_list_iterator last = Fstations.end();
+             
+             
+             // double az1, az2, s;
+             SGVec3d aircraft = SGVec3d::fromGeod(aPos);
+             double d;
+             for(; current != last; ++current) {
+                 if((current->type == tp) || (tp == INVALID)) {
+                     d = distSqr(aircraft, current->cart);
+                     // NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt.
+                     if ( d < (current->range * SG_NM_TO_METER
+                          * current->range * SG_NM_TO_METER ) ) {
+                         stations->push_back(*current);
+                         ++found;
+                     }
+                 }
+             }
+         }
+     }
+     return found;
 }
 
 
@@ -213,41 +207,39 @@ int FGCommList::FindByPos(double lon, double lat, double elev, double range, com
 // Note that the search algorithm starts at 10 miles and multiplies by 10 thereafter, so if
 // say 300 miles is specifed 10, then 100, then 1000 will be searched, breaking at first result 
 // and giving up after 1000.
-double FGCommList::FindClosest( double lon, double lat, double elev, ATCData& ad, atc_type tp, double max_range) {
-       int num_stations = 0;
-       int range = 10;
-       comm_list_type stations;
-       comm_list_iterator itr;
-       double distance = -9999.0;
-       
-       while(num_stations == 0) {
-               num_stations = FindByPos(lon, lat, elev, range, &stations, tp);
-               if(num_stations) {
-                       double closest = max_range * SG_NM_TO_METER;
-                       double tmp;
-                       for(itr = stations.begin(); itr != stations.end(); ++itr) {     
-                               ATCData ad2 = *itr;
-                               SGGeod p1 = SGGeod::fromDegM(ad2.lon, ad2.lat, ad2.elev);
-                               const FGAirport *a = fgFindAirportID(ad2.ident);
-                               if (a) {
-                                       SGGeod p2 = SGGeod::fromDegM(lon, lat, elev);
-                                       tmp = dclGetHorizontalSeparation(p1, p2);
-                                       if(tmp <= closest) {
-                                               closest = tmp;
-                                               distance = tmp;
-                                               ad = *itr;
-                                       }
-                               }
-                       }
-                       //cout << "Closest station is " << ad.ident << " at a range of " << distance << " meters\n";
-                       return(distance);
-               }
-               if(range > max_range) {
-                       break;
-               }
-               range *= 10;
-       }
-       return(-9999.0);
+double FGCommList::FindClosest(const SGGeod& aPos, ATCData& ad, atc_type tp, double max_range) {
+    int num_stations = 0;
+    int range = 10;
+    comm_list_type stations;
+    comm_list_iterator itr;
+    double distance = -9999.0;
+    
+    while(num_stations == 0) {
+        num_stations = FindByPos(aPos, range, &stations, tp);
+        if(num_stations) {
+            double closest = max_range * SG_NM_TO_METER;
+            double tmp;
+            for(itr = stations.begin(); itr != stations.end(); ++itr) { 
+                ATCData ad2 = *itr;    
+                const FGAirport *a = fgFindAirportID(ad2.ident);
+                if (a) {
+                    tmp = dclGetHorizontalSeparation(ad2.geod, aPos);
+                    if(tmp <= closest) {
+                        closest = tmp;
+                        distance = tmp;
+                        ad = *itr;
+                    }
+                }
+            }
+            //cout << "Closest station is " << ad.ident << " at a range of " << distance << " meters\n";
+            return(distance);
+        }
+        if(range > max_range) {
+            break;
+        }
+        range *= 10;
+    }
+    return(-9999.0);
 }
 
 
@@ -257,72 +249,53 @@ double FGCommList::FindClosest( double lon, double lat, double elev, ATCData& ad
 bool FGCommList::FindByCode( const string& ICAO, ATCData& ad, atc_type tp ) {
     const FGAirport *a = fgFindAirportID( ICAO);
     if ( a) {
-               comm_list_type stations;
-               int found = FindByPos(a->getLongitude(), a->getLatitude(), a->getElevation(), 10.0, &stations, tp);
-               if(found) {
-                       comm_list_iterator itr = stations.begin();
-                       while(itr != stations.end()) {
-                               if(((*itr).ident == ICAO) && ((*itr).type == tp)) {
-                                       ad = *itr;
-                                       return true;
-                               }
-                               ++itr;
-                       }
-               }
-    } else {
-        return false;
+        comm_list_type stations;
+        int found = FindByPos(a->geod(), 10.0, &stations, tp);
+        if(found) {
+            comm_list_iterator itr = stations.begin();
+            while(itr != stations.end()) {
+                if(((*itr).ident == ICAO) && ((*itr).type == tp)) {
+                    ad = *itr;
+                    //cout << "FindByCode returns " << ICAO
+                    //     << "  type: " << tp
+                    //   << "  freq: " << itr->freq
+                    //   << endl;
+                    return true;
+                }
+                ++itr;
+            }
+        }
     }
-       return false;
+    return false;
 }
 
-
 // TODO - this function should move somewhere else eventually!
-// Return an appropriate call-sign for an ATIS transmission.
-int FGCommList::GetCallSign( const string& apt_id, int hours, int mins )
+// Return an appropriate sequence number for an ATIS transmission.
+// Return sequence number + 2600 if sequence is unchanged since 
+// last time.
+int FGCommList::GetAtisSequence( const string& apt_id, 
+        const double tstamp, const int interval, const int special)
 {
-       atis_transmission_type tran;
-       
-       if(atislog.find(apt_id) == atislog.end()) {
-               // This station has not transmitted yet - return a random identifier
-               // and add the transmission to the log
-               tran.hours = hours;
-               tran.mins = mins;
-               sg_srandom_time();
-               tran.callsign = int(sg_random() * 25) + 1;      // This *should* give a random int between 1 and 26
-               //atislog[apt_id].push_back(tran);
-               atislog[apt_id] = tran;
-       } else {
-               // This station has transmitted - calculate the appropriate identifier
-               // and add the transmission to the log if it has changed
-               tran = atislog[apt_id];
-               // This next bit assumes that no-one comes back to the same ATIS station
-               // after running FlightGear for more than 24 hours !!
-               if((tran.hours == hours) && (tran.mins == mins)) {
-                       return(tran.callsign);
-               } else {
-                       if(tran.hours == hours) {
-                               // The minutes must have changed
-                               tran.mins = mins;
-                               tran.callsign++;
-                       } else {
-                               if(hours < tran.hours) {
-                                       hours += 24;
-                               }
-                               tran.callsign += (hours - tran.hours);
-                               if(mins != 0) {
-                                       // Assume transmissions were made on every hour
-                                       tran.callsign++;
-                               }
-                               tran.hours = hours;
-                               tran.mins = mins;
-                       }
-                       // Wrap if we've exceeded Zulu
-                       if(tran.callsign > 26) {
-                               tran.callsign -= 26;
-                       }
-                       // And write the new transmission to the log
-                       atislog[apt_id] = tran;
-               }
-       }
-       return(tran.callsign);
+    atis_transmission_type tran;
+    
+    if(atislog.find(apt_id) == atislog.end()) { // New station
+      tran.tstamp = tstamp - interval;
+// Random number between 0 and 25 inclusive, i.e. 26 equiprobable outcomes:
+      tran.sequence = int(sg_random() * LTRS);
+      atislog[apt_id] = tran;
+      //cout << "New ATIS station: " << apt_id << " seq-1: "
+      //      << tran.sequence << endl;
+    } 
+
+// calculate the appropriate identifier and update the log
+    tran = atislog[apt_id];
+
+    int delta = int((tstamp - tran.tstamp) / interval);
+    tran.tstamp += delta * interval;
+    if (special && !delta) delta++;     // a "special" ATIS update is required
+    tran.sequence = (tran.sequence + delta) % LTRS;
+    atislog[apt_id] = tran;
+    //if (delta) cout << "New ATIS sequence: " << tran.sequence
+    //      << "  Delta: " << delta << endl;
+    return(tran.sequence + (delta ? 0 : LTRS*1000));
 }