]> git.mxchange.org Git - flightgear.git/blobdiff - src/ATC/trafficcontrol.cxx
Merge branch 'durk/traffic'
[flightgear.git] / src / ATC / trafficcontrol.cxx
index 0f7b868575ad594f440e8ad4a2df879a5de2ea41..f9c2fee4e5fc6ef900774085e07a755e1f5fe533 100644 (file)
@@ -44,7 +44,9 @@ FGTrafficRecord::FGTrafficRecord() :
    heading(0), 
    speed(0), 
    altitude(0), 
-   radius(0) {
+   radius(0),
+   frequencyId(0),
+   allowTransmission(true) {
 }
 
 void FGTrafficRecord::setPositionAndIntentions(int pos, FGAIFlightPlan *route)
@@ -248,7 +250,7 @@ bool FGTrafficRecord::isOpposing (FGGroundNetwork *net, FGTrafficRecord &other,
       
        for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
        {
-         if (opp = net->findSegment(other.currentPos)->opposite())
+         if ((opp = net->findSegment(other.currentPos)->opposite()))
            {
              if ((*i) > 0)
                if (opp->getIndex() == net->findSegment(*i)->getIndex())
@@ -264,10 +266,10 @@ bool FGTrafficRecord::isOpposing (FGGroundNetwork *net, FGTrafficRecord &other,
          if (other.intentions.size())
            {
              for (intVecIterator j = other.intentions.begin(); j != other.intentions.end(); j++)
-               {  
+               {
                  // cerr << "Current segment 1 " << (*i) << endl;
                  if ((*i) > 0) {
-                   if (opp = net->findSegment(*i)->opposite())
+                   if ((opp = net->findSegment(*i)->opposite()))
                      {
                        if (opp->getIndex() == 
                            net->findSegment(*j)->getIndex())
@@ -303,6 +305,21 @@ void FGTrafficRecord::setHeadingAdjustment(double heading)
   instruction.setHeading(heading); 
 }
 
+bool FGTrafficRecord::pushBackAllowed() {
+      double course, az2,dist;
+       SGGeod curr(SGGeod::fromDegM(getLongitude(),
+                                       getLatitude(), 
+                                       getAltitude()));
+
+      double userLatitude  = fgGetDouble("/position/latitude-deg");
+      double userLongitude = fgGetDouble("/position/longitude-deg");
+      SGGeod user(SGGeod::fromDeg(userLongitude,userLatitude));
+      SGGeodesy::inverse(curr, user, course, az2, dist);
+      //cerr << "Distance to user : " << dist << endl;
+      return (dist > 250);
+
+}
+
 
 
 /***************************************************************************
@@ -318,9 +335,9 @@ FGATCInstruction::FGATCInstruction()
   changeAltitude = false;
   resolveCircularWait = false;
 
-  double speed   = 0;
-  double heading = 0;
-  double alt     = 0;
+  speed   = 0;
+  heading = 0;
+  alt     = 0;
 }
 
 bool FGATCInstruction::hasInstruction()
@@ -337,65 +354,113 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
 {
     string sender, receiver;
     int stationFreq = 0;
-    //double commFreqD;
-    switch (msgDir) {
-         case ATC_AIR_TO_GROUND:
-             sender = rec->getAircraft()->getTrafficRef()->getCallSign();
-             switch (rec->getLeg()) {
-                 case 2:
-                     stationFreq =
-                        rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency();
-                     receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
-                     break;
-                 case 3: 
-                     receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
-                     break;
-                 case 4: 
-                     receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Tower";
-                     break;
-             }
-             break;
-         case ATC_GROUND_TO_AIR:
-             receiver = rec->getAircraft()->getTrafficRef()->getCallSign();
-             switch (rec->getLeg()) {
-                 case 2:
-                 stationFreq =
-                        rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency();
-                     sender = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
-                     break;
-                 case 3: 
-                     sender = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
-                     break;
-                 case 4: 
-                     sender = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Tower";
-                     break;
-             }
-             break;
-         }
+    int taxiFreq    = 0;
+    int freqId      = 0;
+    string atisInformation;
     string text;
+    string taxiFreqStr;
+    double heading = 0;
+    string activeRunway;
+    string fltType;
+    string rwyClass;
+    string SID;
+    string transponderCode;
+    FGAIFlightPlan *fp;
+    string fltRules;
+
+    //double commFreqD;
+    sender = rec->getAircraft()->getTrafficRef()->getCallSign();
+    switch (rec->getLeg()) {
+        case 2:
+        case 3:
+            freqId = rec->getNextFrequency();
+            stationFreq =
+            rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency(rec->getLeg()+freqId);
+            taxiFreq =
+            rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency(3);
+            receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
+            atisInformation = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getAtisInformation();
+            break;
+        case 4: 
+            receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Tower";
+            break;
+    }
+    // Swap sender and receiver value in case of a ground to air transmission
+    if (msgDir == ATC_GROUND_TO_AIR) {
+       string tmp = sender;
+       sender = receiver;
+       receiver = tmp;
+    }
     switch (msgId) {
           case MSG_ANNOUNCE_ENGINE_START:
                text = sender + ". Ready to Start up";
                break;
           case MSG_REQUEST_ENGINE_START:
                text = receiver + ", This is " + sender + ". Position " +getGateName(rec->getAircraft()) +
-                       ". Information YY." +
+                       ". Information " + atisInformation + ". " +
                        rec->getAircraft()->getTrafficRef()->getFlightRules() + " to " + 
                        rec->getAircraft()->getTrafficRef()->getArrivalAirport()->getName() + ". Request start-up";
                break;
+          // Acknowledge engine startup permission
+          // Assign departure runway
+          // Assign SID, if necessery (TODO)
           case MSG_PERMIT_ENGINE_START:
-               text = receiver + ". Start-up approved. YY correct, runway ZZ, AAA departure, squawk BBBB. " +
-                      "For push-back and taxi clearance call CCC.CCC. " + sender + " control.";
+               taxiFreqStr = formatATCFrequency3_2(taxiFreq);
+
+               heading = rec->getAircraft()->getTrafficRef()->getCourse();
+               fltType = rec->getAircraft()->getTrafficRef()->getFlightType();
+               rwyClass= rec->getAircraft()->GetFlightPlan()->getRunwayClassFromTrafficType(fltType);
+
+               rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
+               rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway);
+               fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getSID(activeRunway, heading);
+               rec->getAircraft()->GetFlightPlan()->setSID(fp);
+               if (fp) {
+                   SID = fp->getName() + " departure";
+               } else {
+                   SID = "fly runway heading ";
+               }
+               //snprintf(buffer, 7, "%3.2f", heading);
+               fltRules = rec->getAircraft()->getTrafficRef()->getFlightRules();
+               transponderCode = genTransponderCode(fltRules);
+               rec->getAircraft()->SetTransponderCode(transponderCode);
+               text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " + activeRunway
+                       + ", " + SID + ", squawk " + transponderCode + ". " +
+                      "For push-back and taxi clearance call " + taxiFreqStr + ". " + sender + " control.";
                break;
           case MSG_DENY_ENGINE_START:
                text = receiver + ". Standby";
                break;
          case MSG_ACKNOWLEDGE_ENGINE_START:
-               text = receiver + ". Start-up approved. YY correct, runway ZZ, AAA departure, squawk BBBB. " +
-                      "For push-back and taxi clearance call CCC.CCC. " + sender;
+               fp = rec->getAircraft()->GetFlightPlan()->getSID();
+               if (fp) {
+                  SID = rec->getAircraft()->GetFlightPlan()->getSID()->getName() + " departure";
+               } else {
+                  SID = "fly runway heading ";
+               }
+               taxiFreqStr = formatATCFrequency3_2(taxiFreq);
+               activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
+               transponderCode = rec->getAircraft()->GetTransponderCode();
+               text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " +
+                      activeRunway + ", " + SID + ", squawk " + transponderCode + ". " +
+                      "For push-back and taxi clearance call " + taxiFreqStr + ". " + sender;
                break;
-           default:
+           case MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY:
+               taxiFreqStr = formatATCFrequency3_2(taxiFreq);
+               text = receiver + ". Switching to " + taxiFreqStr + ". " + sender;
                break;
+           case MSG_REQUEST_PUSHBACK_CLEARANCE:
+               text = receiver + ". Request push-back. " + sender;
+               break;
+           case MSG_PERMIT_PUSHBACK_CLEARANCE:
+               text = receiver + ". Push-back approved. " + sender;
+               break;
+           case MSG_HOLD_PUSHBACK_CLEARANCE:
+                text = receiver + ". Standby. " + sender;
+                 break;
+            default:
+                 text = sender + ". Transmitting unknown Message";
+                  break;
     }
     double onBoardRadioFreq0 = fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
     double onBoardRadioFreq1 = fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
@@ -407,11 +472,29 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
     // the relevant frequency.
     // Note that distance attenuation is currently not yet implemented
     if ((onBoardRadioFreqI0 == stationFreq) || (onBoardRadioFreqI1 == stationFreq)) {
-        fgSetString("/sim/messages/atc", text.c_str());
-        //cerr << "Printing Message: " << endl;
+        if (rec->allowTransmissions()) {
+            fgSetString("/sim/messages/atc", text.c_str());
+        }
     }
 }
 
+string FGATCController::formatATCFrequency3_2(int freq) {
+    char buffer[7];
+    snprintf(buffer, 7, "%3.2f", ( (float) freq / 100.0) );
+    return string(buffer);
+}
+
+// TODO: Set transponder codes according to real-world routes.
+// The current version just returns a random string of four octal numbers. 
+string FGATCController::genTransponderCode(string fltRules) {
+    if (fltRules == "VFR") {
+        return string("1200");
+    } else {
+        char buffer[5];
+        snprintf(buffer, 5, "%d%d%d%d", rand() % 8, rand() % 8,rand() % 8, rand() % 8);
+        return string(buffer);
+    }
+}
 
 /***************************************************************************
  * class FGTowerController
@@ -791,9 +874,44 @@ void FGStartupController::update(int id, double lat, double lon, double heading,
              available = false;
         }
      }
+     // Note: The next two stages are only necessesary when Startup control is
+     //  on a different frequency, compared to ground control
+     if ((state == 4) && available){
+        if (now > startTime+130) {
+            transmit(&(*i), MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY, ATC_AIR_TO_GROUND);
+            i->updateState();
+            i->nextFrequency();
+            lastTransmission = now;
+             available = false;
+        }
+     }
+
+
      // TODO: Switch to APRON control and request pushback Clearance.
      // Get Push back clearance
-     if ((state == 4) && available){
+     if ((state == 5) && available){
+        if (now > startTime+160) {
+            transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND);
+            i->updateState();
+            lastTransmission = now;
+             available = false;
+        }
+     }
+     if ((state == 6) && available){
+        if (now > startTime+180) {
+            if (i->pushBackAllowed()) {
+                 i->allowRepeatedTransmissions();
+                 transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE, ATC_GROUND_TO_AIR);
+                 i->updateState();
+            } else {
+                 transmit(&(*i), MSG_HOLD_PUSHBACK_CLEARANCE, ATC_GROUND_TO_AIR);
+                 i->suppressRepeatedTransmissions();
+            }
+            lastTransmission = now;
+             available = false;
+        }
+     }
+     if ((state == 6) && available){
           i->setHoldPosition(false);
      }
 }