1 // tcas.hxx -- Traffic Alert and Collision Avoidance System (TCAS)
2 //
3 // Written by Thorsten Brehm, started December 2010.
4 //
5 // Copyright (C) 2010 Thorsten Brehm - brehmt (at) gmail com
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
20 
21 #ifndef __INSTRUMENTS_TCAS_HXX
22 #define __INSTRUMENTS_TCAS_HXX
23 
24 #include <assert.h>
25 
26 #include <vector>
27 #include <deque>
28 #include <map>
29 
30 #include <simgear/props/props.hxx>
31 #include <simgear/structure/subsystem_mgr.hxx>
32 #include <Sound/voiceplayer.hxx>
33 
34 using std::vector;
35 using std::deque;
36 using std::map;
37 
38 class SGSampleGroup;
39 
40 #include <Main/globals.hxx>
41 
42 #ifdef _MSC_VER
43 #  pragma warning( push )
44 #  pragma warning( disable: 4355 )
45 #endif
46 
47 ///////////////////////////////////////////////////////////////////////////////
48 // TCAS  //////////////////////////////////////////////////////////////////////
49 ///////////////////////////////////////////////////////////////////////////////
50 
51 class TCAS : public SGSubsystem
52 {
53     typedef enum
54     {
55         AdvisoryClear         = 0,                          /*< Clear of traffic */
56         AdvisoryIntrusion     = 1,                          /*< Intrusion flag */
57         AdvisoryClimb         = AdvisoryIntrusion|(1 << 1), /*< RA climb */
58         AdvisoryDescend       = AdvisoryIntrusion|(1 << 2), /*< RA descend */
59         AdvisoryAdjustVSpeed  = AdvisoryIntrusion|(1 << 3), /*< RA adjust vertical speed (TCAS II 7.0 only) */
60         AdvisoryMaintVSpeed   = AdvisoryIntrusion|(1 << 4), /*< RA maintain vertical speed */
61         AdvisoryMonitorVSpeed = AdvisoryIntrusion|(1 << 5), /*< RA monitor vertical speed */
62         AdvisoryLevelOff      = AdvisoryIntrusion|(1 << 6)  /*< RA level off (TCAS II 7.1 only) */
63     } EnumAdvisory;
64 
65     typedef enum
66     {
67         OptionNone            = 0,        /*< no option modifier */
68         OptionIncreaseClimb   = (1 << 0), /*< increase climb */
69         OptionIncreaseDescend = (1 << 1), /*< increase descend */
70         OptionCrossingClimb   = (1 << 2), /*< crossing climb */
71         OptionCrossingDescent = (1 << 3)  /*< crossing descent */
72     } EnumAdvisoryOption;
73 
74     typedef enum
75     {
76         SwitchOff        = 0, /*< TCAS switched off */
77         SwitchStandby    = 1, /*< TCAS standby (no TA/RA) */
78         SwitchTaOnly     = 2, /*< TCAS in TA-only mode (no RA) */
79         SwitchAuto       = 3  /*< TCAS in TA/RA mode */
80     } EnumModeSwitch;
81 
82     typedef enum
83     {
84         ThreatInvisible    = -1,/*< Traffic is invisible to TCAS (i.e. no transponder) */
85         ThreatNone         = 0, /*< Traffic is visible but no threat. */
86         ThreatProximity    = 1, /*< Proximity intruder traffic (no threat). */
87         ThreatTA           = 2, /*< TA-level threat traffic. */
88         ThreatRA           = 3  /*< RA-level threat traffic. */
89     } EnumThreatLevel;
90 
91     typedef struct
92     {
93       int  threatLevel;  /*< intruder threat level: 0=clear, 1=proximity,
94                              2=intruder, 3=proximity intruder */
95       int  RA;           /*< resolution advisory */
96       int  RAOption;     /*< option flags for advisory */
97     } ResolutionAdvisory;
98 
99     typedef struct
100     {
101         float Tau;       /*< vertical/horizontal protection range in seconds */
102         float DMOD;      /*< horizontal protection range in nm */
103         float ALIM;      /*< vertical protection range in ft */
104     } Thresholds;
105 
106     typedef struct
107     {
108         double    maxAltitude; /*< max altitude for this sensitivity level */
109         int        sl;         /*< sensitivity level */
110         Thresholds TA;         /*< thresholds for TA-level threats */
111         Thresholds RA;         /*< thresholds for RA-level threats */
112     } SensitivityLevel;
113 
114     typedef struct
115     {
116         std::string callsign;
117         bool   verticalTA;
118         bool   verticalRA;
119         bool   horizontalTA;
120         bool   horizontalRA;
121         bool   isTracked;
122         float  horizontalTau;
123         float  verticalTau;
124         float  relativeAltitudeFt;
125         float  verticalFps;
126         int    RASense;
127     } ThreatInfo;
128 
129     typedef struct
130     {
131         int    threatLevel;
132         double TAtimestamp;
133         double RAtimestamp;
134     } TrackerTarget;
135 
136     typedef map<std::string,TrackerTarget*> TrackerTargets;
137 
138     typedef struct
139     {
140         double lat;
141         double lon;
142         float  pressureAltFt;
143         float  radarAltFt;
144         float  heading;
145         float  velocityKt;
146         float  verticalFps;
147     } LocalInfo; /*< info structure for local aircraft */
148 
149     /////////////////////////////////////////////////////////////////////////////
150     // TCAS::PropertiesHandler ///////////////////////////////////////////////
151     /////////////////////////////////////////////////////////////////////////////
152 
153     class PropertiesHandler : public FGVoicePlayer::PropertiesHandler
154     {
155     public:
PropertiesHandler(TCAS *)156         PropertiesHandler (TCAS *) :
157             FGVoicePlayer::PropertiesHandler() {}
158 
PropertiesHandler(void)159         PropertiesHandler (void) : FGVoicePlayer::PropertiesHandler() {}
160     };
161 
162     /////////////////////////////////////////////////////////////////////////////
163     // TCAS::VoicePlayer ////////////////////////////////////////////////////////
164     /////////////////////////////////////////////////////////////////////////////
165 
166     class VoicePlayer :
167         public FGVoicePlayer
168     {
169     public:
VoicePlayer(TCAS * tcas)170         VoicePlayer (TCAS* tcas) :
171             FGVoicePlayer(&tcas->properties_handler, "tcas") {}
172 
~VoicePlayer(void)173         ~VoicePlayer (void) {}
174 
175         void init    (void);
176 
177         struct
178         {
179             Voice* pTrafficTraffic;
180             Voice* pClimb;
181             Voice* pClimbNow;
182             Voice* pClimbCrossing;
183             Voice* pClimbIncrease;
184             Voice* pDescend;
185             Voice* pDescendNow;
186             Voice* pDescendCrossing;
187             Voice* pDescendIncrease;
188             Voice* pClear;
189             Voice* pAdjustVSpeed;
190             Voice* pMaintVSpeed;
191             Voice* pMonitorVSpeed;
192             Voice* pLevelOff;
193             Voice* pTestOk;
194             Voice* pTestFail;
195         } Voices;
196     private:
197         SGPropertyNode_ptr nodeSoundFilePrefix;
198     };
199 
200     /////////////////////////////////////////////////////////////////////////////
201     // TCAS::Annunciator ////////////////////////////////////////////////////////
202     /////////////////////////////////////////////////////////////////////////////
203 
204     class Annunciator
205     {
206     public:
207         Annunciator    (TCAS* tcas);
~Annunciator(void)208         ~Annunciator   (void) {}
209         void bind      (SGPropertyNode* node);
210         void init      (void);
211         void update    (void);
212 
213         void trigger   (const ResolutionAdvisory& newAdvisory, bool revertedRA);
214         void test      (bool testOk);
215         void clear     (void);
isPlaying(void)216         bool isPlaying (void) { return voicePlayer.is_playing();}
217 
218     private:
219         TCAS* tcas;
220         ResolutionAdvisory previous;
221         FGVoicePlayer::Voice* pLastVoice;
222         VoicePlayer voicePlayer;
223         SGPropertyNode_ptr nodeGpwsAlertOn;
224     };
225 
226     /////////////////////////////////////////////////////////////////////////////
227     // TCAS::AdvisoryCoordinator ////////////////////////////////////////////////
228     /////////////////////////////////////////////////////////////////////////////
229 
230     class AdvisoryCoordinator
231     {
232     public:
233         AdvisoryCoordinator  (TCAS* _tcas);
~AdvisoryCoordinator(void)234         ~AdvisoryCoordinator (void) {}
235 
236         void bind            (SGPropertyNode* node);
237         void init            (void);
238         void reinit          (void);
239         void update          (int mode);
240 
241         void clear           (void);
242         void add             (const ResolutionAdvisory& newAdvisory);
243 
244     private:
245         TCAS* tcas;
246         double lastTATime;
247         ResolutionAdvisory current;
248         ResolutionAdvisory previous;
249         SGPropertyNode_ptr nodeTAWarning;
250     };
251 
252     /////////////////////////////////////////////////////////////////////////////
253     // TCAS::Tracker ////////////////////////////////////////////////////////////
254     /////////////////////////////////////////////////////////////////////////////
255 
256     class Tracker
257     {
258     public:
259         Tracker  (TCAS* _tcas);
~Tracker(void)260         ~Tracker (void) {}
261 
262         void update          (void);
263 
264         void add             (const std::string callsign, int detectedLevel);
active(void)265         bool active          (void) { return haveTargets;}
newTraffic(void)266         bool newTraffic      (void) { return newTargets;}
isTracked(std::string callsign)267         bool isTracked       (std::string callsign) { if (!haveTargets) return false;else return _isTracked(callsign);}
268         bool _isTracked      (std::string callsign);
269         int  getThreatLevel  (std::string callsign);
270 
271     private:
272         double currentTime;
273         bool   haveTargets;
274         bool   newTargets;
275         TrackerTargets targets;
276     };
277 
278     /////////////////////////////////////////////////////////////////////////////
279     // TCAS::AdvisoryGenerator //////////////////////////////////////////////////
280     /////////////////////////////////////////////////////////////////////////////
281 
282     class AdvisoryGenerator
283     {
284     public:
285         AdvisoryGenerator        (TCAS* _tcas);
~AdvisoryGenerator(void)286         ~AdvisoryGenerator       (void) {}
287 
288         void init                (const LocalInfo* _pSelf, ThreatInfo* _pCurrentThreat);
289 
290         void setAlarmThresholds  (const SensitivityLevel* _pAlarmThresholds);
291 
292         int   resolution         (int mode, int threatLevel, float distanceNm,
293                                   float altFt, float heading, float velocityKt);
294 
295     private:
296         float verticalSeparation (float newVerticalFps);
297         void  determineRAsense   (int& RASense, bool& isCrossing);
298 
299     private:
300         TCAS*             tcas;
301         const LocalInfo*  pSelf;          /*< info structure for local aircraft */
302         ThreatInfo* pCurrentThreat; /*< info structure on current intruder/threat */
303         const SensitivityLevel* pAlarmThresholds;
304     };
305 
306     /////////////////////////////////////////////////////////////////////////////
307     // TCAS::ThreatDetector /////////////////////////////////////////////////////
308     /////////////////////////////////////////////////////////////////////////////
309 
310     class ThreatDetector
311     {
312     public:
313         ThreatDetector            (TCAS* _tcas);
~ThreatDetector(void)314         ~ThreatDetector           (void) {}
315 
316         void  init                (void);
317         void  update              (void);
318 
319         bool  checkTransponder    (const SGPropertyNode* pModel, float velocityKt);
320         int   checkThreat         (int mode, const SGPropertyNode* pModel);
321         void  checkVerticalThreat (void);
322         void  horizontalThreat    (float bearing, float distanceNm, float heading,
323                                    float velocityKt);
324 
setPressureAlt(float altFt)325         void  setPressureAlt      (float altFt) { self.pressureAltFt = altFt;}
getPressureAlt(void)326         float getPressureAlt      (void)        { return self.pressureAltFt;}
327 
setRadarAlt(float altFt)328         void  setRadarAlt         (float altFt) { self.radarAltFt = altFt;}
getRadarAlt(void)329         float getRadarAlt         (void)        { return self.radarAltFt;}
330 
getVelocityKt(void)331         float getVelocityKt       (void)        { return self.velocityKt;}
getRASense(void)332         int   getRASense          (void)        { return currentThreat.RASense;}
333 
334     private:
335         void  unitTest            (void);
336 
337     private:
338         static const SensitivityLevel sensitivityLevels[];
339 
340         TCAS*              tcas;
341 #ifdef FEATURE_TCAS_DEBUG_THREAT_DETECTOR
342         int                checkCount;
343 #endif // of FEATURE_TCAS_DEBUG_THREAT_DETECTOR
344 
345         SGPropertyNode_ptr nodeLat;
346         SGPropertyNode_ptr nodeLon;
347         SGPropertyNode_ptr nodePressureAlt;
348         SGPropertyNode_ptr nodeRadarAlt;
349         SGPropertyNode_ptr nodeHeading;
350         SGPropertyNode_ptr nodeVelocity;
351         SGPropertyNode_ptr nodeVerticalFps;
352 
353         LocalInfo          self;          /*< info structure for local aircraft */
354         ThreatInfo         currentThreat; /*< info structure on current intruder/threat */
355         const SensitivityLevel* pAlarmThresholds;
356     };
357 
358 private:
359     std::string              name;
360     int                 num;
361     double              nextUpdateTime;
362     int                 selfTestStep;
363 
364     SGPropertyNode_ptr  nodeModeSwitch;
365     SGPropertyNode_ptr  nodeServiceable;
366     SGPropertyNode_ptr  nodeSelfTest;
367     SGPropertyNode_ptr  nodeDebugTrigger;
368     SGPropertyNode_ptr  nodeDebugRA;
369     SGPropertyNode_ptr  nodeDebugThreat;
370 
371     PropertiesHandler   properties_handler;
372     ThreatDetector      threatDetector;
373     Tracker             tracker;
374     AdvisoryCoordinator advisoryCoordinator;
375     AdvisoryGenerator   advisoryGenerator;
376     Annunciator         annunciator;
377 
378 private:
379     void selfTest       (void);
380 
381 public:
382     TCAS (SGPropertyNode* node);
383 
384     // Subsystem API.
385     void bind() override;
386     void init() override;
387     void reinit() override;
388     void unbind() override;
389     void update(double dt) override;
390 
391     // Subsystem identification.
staticSubsystemClassId()392     static const char* staticSubsystemClassId() { return "tcas"; }
393 
394     /* configuration options */
395     int  _verticalRange;
396     int  _lateralRange;
397     int  _proxVertRange;
398     int  _proxLatRange;
399     int  _incDesInhbAlt;
400     int  _DesInhbAlt;
401     int  _RAInhbAlt;
402     int  _TAInhbAlt;
403     int  _intruderInhbAlt;
404     bool _intruderInhbSelfAltToggle;
405     int  _intruderInhbSelfAlt;
406 };
407 
408 #ifdef _MSC_VER
409 #  pragma warning( pop )
410 #endif
411 
412 #endif // __INSTRUMENTS_TCAS_HXX
413