15#include <osg/Geometry>
16#include <osg/MatrixTransform>
19#include <simgear/scene/material/EffectGeode.hxx>
20#include <simgear/scene/material/mat.hxx>
21#include <simgear/scene/material/matlib.hxx>
22#include <simgear/scene/util/OsgMath.hxx>
23#include <simgear/timing/sg_time.hxx>
98 int state = (*i)->getState();
99 if ((state >= minState) && (state <= maxState) &&
available) {
101 SG_LOG(SG_ATC, SG_BULK,
"Checking state " << state <<
" for " << (*i)->getAircraft()->getCallSign());
102 SGPropertyNode_ptr trans_num =
globals->get_props()->getNode(
"/sim/atc/transmission-num",
true);
103 int n = trans_num->getIntValue();
105 trans_num->setIntValue(-1);
107 SG_LOG(SG_ATC, SG_DEBUG,
"Selected transmission message " << n);
111 SG_LOG(SG_ATC, SG_BULK,
"Sending message for " << (*i)->getAircraft()->getCallSign());
128 string sender, receiver;
132 string atisInformation;
141 string transponderCode;
144 string instructionText;
145 int ground_to_air = 0;
148 sender =
rec->getCallsign();
149 if (
rec->getAircraft()->getTaxiClearanceRequest()) {
150 instructionText =
"push-back and taxi";
152 instructionText =
"taxi";
155 SG_LOG(SG_ATC, SG_BULK,
"transmitting for: " << sender <<
" at Leg " <<
rec->getLeg());
158 auto depApt =
rec->getAircraft()->getTrafficRef()->getDepartureAirport();
159 auto arrApt =
rec->getAircraft()->getTrafficRef()->getArrivalAirport();
162 SG_LOG(SG_ATC, SG_DEV_ALERT,
"TrafficRec has empty departure airport, can't transmit");
166 SG_LOG(SG_ATC, SG_DEV_ALERT,
"TrafficRec has empty arrival airport, can't transmit");
171 taxiFreq = depApt->getDynamics()->getGroundFrequency(2);
172 towerFreq = depApt->getDynamics()->getTowerFrequency(2);
174 atisInformation = depApt->getDynamics()->getAtisSequence();
186 text = sender +
". Ready to Start up.";
190 receiver +
", This is " + sender +
". Position " +
192 atisInformation +
". " +
193 rec->getAircraft()->getTrafficRef()->getFlightRules() +
195 rec->getAircraft()->getTrafficRef()->getArrivalAirport()->getName() +
". Request start-up.";
203 heading =
rec->getAircraft()->getTrafficRef()->getCourse();
204 fltType =
rec->getAircraft()->getTrafficRef()->getFlightType();
206 rec->getAircraft()->GetFlightPlan()->getRunwayClassFromTrafficType(fltType);
208 rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getActiveRunway(rwyClass,
RunwayAction::TAKEOFF, activeRunway,
210 rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway);
212 rec->getAircraft()->GetFlightPlan()->setSID(fp);
214 SID = fp->
getName() +
" departure";
216 SID =
"fly runway heading ";
219 fltRules =
rec->getAircraft()->getTrafficRef()->getFlightRules();
221 rec->getAircraft()->SetTransponderCode(transponderCode);
222 if (stationFreq!=taxiFreq) {
224 receiver +
". Start-up approved. " + atisInformation +
225 " correct, runway " + activeRunway +
", " + SID +
", squawk " +
226 transponderCode +
". " +
227 "For " + instructionText +
" clearance call " + taxiFreqStr +
". " +
228 sender +
" control.";
231 receiver +
". Start-up approved. " + atisInformation +
232 " correct, runway " + activeRunway +
", " + SID +
", squawk " +
233 transponderCode +
". " +
234 sender +
" control.";
238 text = receiver +
". Standby.";
241 fp =
rec->getAircraft()->GetFlightPlan()->getSID();
244 rec->getAircraft()->GetFlightPlan()->getSID()->getName() +
247 SID =
"fly runway heading ";
250 activeRunway =
rec->getAircraft()->GetFlightPlan()->getRunway();
251 transponderCode =
rec->getAircraft()->GetTransponderCode();
253 if (stationFreq!=taxiFreq) {
255 receiver +
". Start-up approved. " + atisInformation +
256 " correct, runway " + activeRunway +
", " + SID +
", squawk " +
257 transponderCode +
". " +
258 "For " + instructionText +
" clearance call " + taxiFreqStr +
". " +
262 receiver +
". Start-up approved. " + atisInformation +
263 " correct, runway " + activeRunway +
", " + SID +
", squawk " +
264 transponderCode +
". " +
270 text = receiver +
". Switching to " + taxiFreqStr +
". " + sender +
".";
273 text = receiver +
". With you. " + sender +
".";
276 text = receiver +
". Roger. " + sender +
".";
279 if (
rec->getAircraft()->getTaxiClearanceRequest()) {
280 text = receiver +
". Request push-back. " + sender +
".";
282 text = receiver +
". Request Taxi clearance. " + sender +
".";
286 if (
rec->getAircraft()->getTaxiClearanceRequest()) {
287 text = receiver +
". Push-back approved. " + sender +
".";
289 text = receiver +
". Cleared to Taxi. " + sender +
".";
293 text = receiver +
". Standby. " + sender +
".";
296 text = receiver +
". Ready to Taxi. " + sender +
".";
299 text = receiver +
". Cleared to taxi. " + sender +
".";
302 text = receiver +
". Cleared to taxi. " + sender +
".";
305 text = receiver +
". Hold Position. " + sender +
".";
308 text = receiver +
". Holding Position. " + sender +
".";
311 text = receiver +
". Resume Taxiing. " + sender +
".";
314 text = receiver +
". Continuing Taxi. " + sender +
".";
317 activeRunway =
rec->getAircraft()->GetFlightPlan()->getRunway();
318 text = receiver +
". Holding short runway " + activeRunway +
". " + sender +
".";
321 activeRunway =
rec->getAircraft()->GetFlightPlan()->getRunway();
322 text = receiver +
" Roger. Holding short runway " + activeRunway +
". " + sender +
".";
325 activeRunway =
rec->getAircraft()->GetFlightPlan()->getRunway();
326 text = receiver +
". Cleared for takeoff runway " + activeRunway +
". " + sender +
".";
329 activeRunway =
rec->getAircraft()->GetFlightPlan()->getRunway();
330 text = receiver +
" Roger. Cleared for takeoff runway " + activeRunway +
". " + sender +
".";
334 text = receiver +
" Contact Tower at " + towerFreqStr +
". " + sender +
".";
338 text = receiver +
" Roger, switching to tower at " + towerFreqStr +
". " + sender +
".";
341 text = receiver +
". " + sender +
" Information delta.";
344 activeRunway =
rec->getRunway();
345 text = receiver +
" expect ILS approach " + activeRunway +
". " + sender;
348 activeRunway =
rec->getRunway();
350 text = receiver +
" runway " + activeRunway +
" cleared to land. " + sender;
353 activeRunway =
rec->getAircraft()->GetFlightPlan()->getRunway();
354 text = receiver +
" runway " + activeRunway +
" cleared to land. " + sender;
357 text = receiver +
" hold as published . " + sender;
360 text = receiver +
" holding as published . " + sender;
363 if(!
rec->getAircraft()->GetFlightPlan()->getParkingGate()) {
364 SG_LOG(SG_ATC, SG_ALERT,
"Flightplan without gate");
367 text = receiver +
" taxi to " +
rec->getAircraft()->GetFlightPlan()->getParkingGate()->getName() +
" . " + sender;
370 if(!
rec->getAircraft()->GetFlightPlan()->getParkingGate()) {
371 SG_LOG(SG_ATC, SG_ALERT,
"Flightplan without gate");
374 text = receiver +
" taxi to " +
rec->getAircraft()->GetFlightPlan()->getParkingGate()->getName() +
" . " + sender;
377 text = text + sender +
". Transmitting unknown Message. MsgId " + std::to_string(msgId);
381 const bool atcAudioEnabled =
fgGetBool(
"/sim/sound/atc/enabled",
false);
382 if (audible && atcAudioEnabled) {
383 double onBoardRadioFreq0 =
384 fgGetDouble(
"/instrumentation/comm[0]/frequencies/selected-mhz");
385 double onBoardRadioFreq1 =
386 fgGetDouble(
"/instrumentation/comm[1]/frequencies/selected-mhz");
387 int onBoardRadioFreqI0 = (int)floor(onBoardRadioFreq0 * 100 + 0.5);
388 int onBoardRadioFreqI1 = (int)floor(onBoardRadioFreq1 * 100 + 0.5);
389 SG_LOG(SG_ATC, SG_DEBUG,
"COM1 : " << onBoardRadioFreq0 <<
" COM2 : " << onBoardRadioFreq1 <<
" Sending to " <<
formatATCFrequency3_2(stationFreq) <<
" Txt : " << text );
390 if (stationFreq == 0) {
391 SG_LOG(SG_ATC, SG_DEBUG,
getName() <<
" stationFreq not found");
398 if ((stationFreq > 0) &&
399 ((onBoardRadioFreqI0 == stationFreq) ||
400 (onBoardRadioFreqI1 == stationFreq))) {
401 if (
rec->allowTransmissions()) {
402 if (
fgGetBool(
"/sim/radio/use-itm-attenuation",
false)) {
403 SG_LOG(SG_ATC, SG_DEBUG,
"Using ITM radio propagation");
407 sender_pos =
parent->parent()->geod();
409 sender_pos =
rec->getPos();
411 double frequency = ((double)stationFreq) / 100;
412 radio->
receiveATC(sender_pos, frequency, text, ground_to_air);
415 SG_LOG(SG_ATC, SG_BULK,
"Transmitting " << text);
430 SG_LOG(SG_ATC, SG_ALERT,
431 "AI error: Aircraft without traffic record " <<
getName() <<
" at " << SG_ORIGIN <<
" list " <<
activeTraffic.empty());
445 aiObject->clearResolveCircularWait();
449 SG_LOG(SG_ATC, SG_DEBUG,
450 "Added " << (aiObject)->getCallsign() <<
"(" << (aiObject)->getId() <<
") " << aiObject);
467 SG_LOG(SG_ATC, SG_ALERT,
468 "AI error: Aircraft without traffic record is signing off from " <<
getName() <<
" at " << SG_ORIGIN <<
" list " <<
activeTraffic.empty());
471 const auto leg = (*i)->getLeg();
478 SG_LOG(SG_ATC, SG_DEV_WARN,
"Couldn't remove from index " << (*
i));
481 SG_LOG(SG_ATC, SG_DEBUG, (*i)->getCallsign() <<
" (" << (*i)->getId() <<
") signing off from " <<
getName() <<
"(" <<
getFrequency() <<
") and removed from AirportGroundradar Leg " << (*i)->getLeg() <<
" at " << (*i)->getPos());
483 SG_LOG(SG_ATC, SG_DEBUG, (*i)->getCallsign() <<
" (" << (*i)->getId() <<
") signing off from " <<
getName() <<
"(" <<
getFrequency() <<
") Leg " << (*i)->getLeg() <<
" at " << (*i)->getPos());
489 SG_LOG(SG_ATC, SG_WARN, (*i)->getCallsign() <<
" (" << (*i)->getId() <<
") not removed ");
491 SG_LOG(SG_ATC, SG_DEBUG, (*i)->getCallsign() <<
" (" << (*i)->getId() <<
") removed from traffic");
501 SG_LOG(SG_ATC, SG_ALERT,
502 "AI error: checking ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
504 return (*i)->hasInstruction();
517 return (*i)->getInstruction();
520 SG_LOG(SG_ATC, SG_ALERT,
"AI error: requesting ATC instruction for aircraft without traffic record from " <<
getName());
534 snprintf(buffer, 8,
"%3.3f", ((
float)freq / 1000.0));
536 snprintf(buffer, 8,
"%3.3f", ((
float)freq / 100.0));
538 return string(buffer);
545 if (fltRules ==
"VFR")
546 return string(
"1200");
548 std::uniform_int_distribution<unsigned> distribution(0, 7);
550 unsigned val = (distribution(
generator) * 1000 +
555 return std::to_string(val);
561 if (traffic->isDead()) {
562 SG_LOG(SG_ATC, SG_DEBUG,
"Remove dead " << traffic->getCallsign() <<
"(" << traffic->getId() <<
") " << traffic->isDead());
566 if (it!=activeTraffic.end()) {
568 bool result = airportGroundRadar->remove(*it);
570 SG_LOG(SG_ATC, SG_DEBUG,
"Couldn't remove from index " << (*it));
574 activeTraffic.erase(it, activeTraffic.end());
585 SG_LOG(SG_ATC, SG_DEBUG,
"searchActiveTraffic empty list");
595 traffic->clearATCController();
const std::string & atGate()
const std::string & getCallSign() const
const std::string & getName()
std::default_random_engine generator
void clearTrafficControllers()
bool hasInstruction(int id)
TrafficVectorIterator searchActiveTraffic(int id) const
Search activeTraffic vector to find matching id.
bool isUserAircraft(FGAIAircraft *)
virtual void handover(SGSharedPtr< FGTrafficRecord > aiObject, int leg)
We share the traffic record much like real life.
virtual ~FGATCController()
virtual void signOff(int id)
Sign off the aircraft with the id from this controller.
FGAirportDynamics * parent
void setAirportGroundRadar(SGSharedPtr< AirportGroundRadar > groundRadar)
SGSharedPtr< FGTrafficRecord > getRecord(int id) const
FGATCInstruction getInstruction(int id)
SGSharedPtr< AirportGroundRadar > airportGroundRadar
TrafficVector activeTraffic
virtual int getFrequency()=0
Returns the frequency to be used.
virtual std::string getName() const =0
void transmit(FGTrafficRecord *rec, FGAirportDynamics *parent, AtcMsgId msgId, AtcMsgDir msgDir, bool audible)
std::string genTransponderCode(const std::string &fltRules)
@ MSG_ACKNOWLEDGE_CLEARED_TO_LAND
@ MSG_ANNOUNCE_ENGINE_START
@ MSG_HOLD_PUSHBACK_CLEARANCE
@ MSG_ACKNOWLEDGE_INITIATE_CONTACT
@ MSG_REQUEST_TAXI_CLEARANCE
@ MSG_ISSUE_TAXI_CLEARANCE
@ MSG_ACKNOWLEDGE_CLEARED_FOR_TAKEOFF
@ MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT
@ MSG_ACKNOWLEDGE_TAXI_PARK
@ MSG_SWITCH_TOWER_FREQUENCY
@ MSG_ACKNOWLEDGE_ARRIVAL
@ MSG_PERMIT_PUSHBACK_CLEARANCE
@ MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY
@ MSG_REQUEST_PUSHBACK_CLEARANCE
@ MSG_ACKNOWLEDGE_ENGINE_START
@ MSG_ACKNOWLEDGE_HOLD_POSITION
@ MSG_ACKNOWLEDGE_RESUME_TAXI
@ MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY
@ MSG_ACKNOWLEDGE_TAXI_CLEARANCE
@ MSG_PERMIT_ENGINE_START
@ MSG_CLEARED_FOR_TAKEOFF
@ MSG_REQUEST_ENGINE_START
@ MSG_REPORT_RUNWAY_HOLD_SHORT
std::string formatATCFrequency3_2(int)
bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId, AtcMsgDir msgDir)
std::string getGateName(FGAIAircraft *aircraft)
void addController(FGATCController *controller)
Adds FGATCController instance to std::vector activeStations.
void removeController(FGATCController *controller)
Searches for and removes FGATCController instance from std::vector activeStations.
void receiveATC(SGGeod tx_pos, double freq, std::string text, int transmission_type)
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
bool fgSetString(char const *name, char const *str)
Set a string value for a property.
std::list< SGSharedPtr< FGTrafficRecord > >::const_iterator TrafficVectorIterator