Skip to content

Commit

Permalink
Add additional rules
Browse files Browse the repository at this point in the history
  • Loading branch information
nabeelio committed Sep 19, 2024
1 parent 50fd9b0 commit ebb3d25
Show file tree
Hide file tree
Showing 21 changed files with 588 additions and 19 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,15 @@ The configuration is a class which has a few different components.
- MSFS - the lookups you enter are LVars
- X-Plane - the looks ups are via datarefs
- FSUIPC - the lookups are offsets
3. `match()`
3. `flapNames` - see below
4. `match()`
- This needs to return a boolean
- A method (`match()`) which passes some information about the starting aircraft
- For MSFS, it's the aircraft ICAO
- For FSX/P3d, the value looked at is the aircraft title field, offset `0x3D00`
- For X-Plane, the value looked at is `sim/aircraft/view/acf_descrip`
- This method can be used to determine if this rule should match
4. Methods for the different features (see below)
5. Methods for the different features (see below)
- The maps - a group of datarefs or offsets which constitute that feature being "on" or "enabled"

In the above example, for the Fenix A320, the landing lights are controlled by two datarefs, both of which the
Expand Down
6 changes: 2 additions & 4 deletions gulpfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,8 @@ export { watchFiles as watch }
*/
export async function clean() {
try {
if (await fs.promises.exists(paths.dist)) {
await deleteAsync([paths.dist])
await Promise.resolve()
}
await deleteAsync([paths.dist])
await Promise.resolve()
} catch (e) {
console.log(e)
}
Expand Down
13 changes: 5 additions & 8 deletions src/aircraft/FenixA320.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,11 @@ export default class FenixA320 extends AircraftConfig {
}

match(title: string, icao: string, config_path: string): boolean {
return (
['Fenix', 'A320'].every((w) => title.includes(w)) ||
['FenixA320'].every((w) => title.includes(w)) ||
['Fenix', 'A321'].every((w) => title.includes(w.toLowerCase())) ||
['FenixA319'].every((w) => title.includes(w.toLowerCase())) ||
['FenixA320'].every((w) => title.includes(w.toLowerCase())) ||
['FenixA321'].every((w) => title.includes(w.toLowerCase()))
)
if (!title.includes('fenix')) {
return false
}

return ['a319', 'a320', 'a321'].some((w) => title.includes(w))
}

beaconLights(value: number): FeatureState {
Expand Down
4 changes: 2 additions & 2 deletions src/rules/beacon_lights.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ export default class BeaconLights implements Rule {
}

return Acars.ViolatedAfterDelay(
this.meta.name,
this.meta.id,
this.meta.delay_time,
() => {
(): RuleValue => {
if (!pirep.isInActiveState) {
return [false]
}
Expand Down
46 changes: 46 additions & 0 deletions src/rules/excess_bank.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Excess bank angle
*/
import { AircraftFeature, PirepState } from '../defs'
import { Meta, Rule, RuleValue } from '../types/rule'
import { Pirep, Telemetry } from '../types/types'

export default class ExcessBank implements Rule {
meta: Meta = {
id: 'EXCESS_BANK',
name: 'Bank angle exceeded limit',
enabled: true, // Default, will change depending on airline config
message: 'Bank angle exceeded limit',
states: [
PirepState.Takeoff,
PirepState.Enroute,
PirepState.Approach,
PirepState.Final,
],
repeatable: false,
cooldown: 60,
max_count: 3,
points: -1,
delay_time: 5000,
parameter: 30, // default, gets overwritten from remote
}

violated(pirep: Pirep, data: Telemetry, previousData?: Telemetry): RuleValue {
if (data.onGround) {
return [false]
}

return Acars.ViolatedAfterDelay(this.meta.id, this.meta.delay_time, () => {
// +Bank is right, -Bank is left
const value =
data.bank < -1 * this.meta.parameter! ||
data.bank > this.meta.parameter!

if (value) {
return [true]
} else {
return [false]
}
})
}
}
35 changes: 35 additions & 0 deletions src/rules/excess_gforce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Detect if there's excess gforces
*/
import { AircraftFeature, PirepState } from '../defs'
import { Meta, Rule, RuleValue } from '../types/rule'
import { Pirep, Telemetry } from '../types/types'

export default class ExcessGForce implements Rule {
meta: Meta = {
id: 'EXCESS_GFORCE',
name: 'GForce exceeded limit',
enabled: true, // Default, will change depending on airline config
message: 'GForce exceeded limit',
states: [
PirepState.Takeoff,
PirepState.Enroute,
PirepState.Approach,
PirepState.Final,
],
repeatable: false,
cooldown: 60,
max_count: 3,
points: -1,
delay_time: 5000,
parameter: 4,
}

violated(pirep: Pirep, data: Telemetry, previousData?: Telemetry): RuleValue {
if (data.onGround) {
return [false]
}

return [data.gForce >= this.meta.parameter!]
}
}
38 changes: 38 additions & 0 deletions src/rules/excess_pitch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Detect is the aircraft is pitched up or down excessively
*/
import { AircraftFeature, PirepState } from '../defs'
import { Meta, Rule, RuleValue } from '../types/rule'
import { Pirep, Telemetry } from '../types/types'

export default class ExcessPitch implements Rule {
meta: Meta = {
id: 'EXCESS_PITCH',
name: 'Pitch exceeded limit',
enabled: true,
message: 'Pitch exceeded limit',
states: [
PirepState.Takeoff,
PirepState.Enroute,
PirepState.Approach,
PirepState.Final,
],
repeatable: false,
cooldown: 60,
max_count: 3,
points: -1,
delay_time: 5000,
parameter: 4,
}

violated(pirep: Pirep, data: Telemetry, previousData?: Telemetry): RuleValue {
if (data.onGround) {
return [false]
}

return [
data.pitch < -1 * this.meta.parameter! ||
data.pitch > this.meta.parameter!,
]
}
}
43 changes: 43 additions & 0 deletions src/rules/excess_taxi_speed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Evaluate if this rule has been violated. If they go overspeed, then start the
* stopwatch. Then mark it as violated if they've gone overspeed for ~ 6 seconds
* 6 seconds to make sure it doesn't interfere with a takeoff roll
*/
import { PirepState } from '../defs'
import { Meta, Rule, RuleValue } from '../types/rule'
import { Pirep, Telemetry } from '../types/types'

export default class ExcessTaxiSpeed implements Rule {
meta: Meta = {
id: 'EXCESS_TAXI_SPEED',
name: 'Taxi speed exceeded limit',
enabled: true,
message: 'Taxi speed exceeded limit',
states: [PirepState.TaxiIn, PirepState.TaxiOut],
repeatable: false,
cooldown: 60,
max_count: 3,
points: -1,
delay_time: 5000,
parameter: 4,
}

violated(pirep: Pirep, data: Telemetry, previousData?: Telemetry): RuleValue {
return Acars.ViolatedAfterDelay(
this.meta.id,
this.meta.delay_time,
(): RuleValue => {
if (!data.onGround) {
return [false]
}

// If they're on a runway, ignore any taxi speed warnings, might be taking off
if (data.approachingRunway != null || data.runway != null) {
return [false]
}

return [data.groundSpeed.Knots > this.meta.parameter!]
},
)
}
}
41 changes: 41 additions & 0 deletions src/rules/fuel_refilled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* If the fuel level is higher at any point
*/
import { PirepState } from '../defs'
import { Meta, Rule, RuleValue } from '../types/rule'
import { Pirep, Telemetry } from '../types/types'

export default class FuelRefilled implements Rule {
meta: Meta = {
id: 'EXCESS_TAXI_SPEED',
name: 'Taxi speed exceeded limit',
enabled: true,
message: 'Taxi speed exceeded limit',
states: [],
repeatable: false,
cooldown: 60,
max_count: 3,
points: -1,
delay_time: 5000,
parameter: 4,
}

violated(pirep: Pirep, data: Telemetry, previousData?: Telemetry): RuleValue {
if (data.onGround || previousData == null) {
return [false]
}

if (data.fuelQuantity.Pounds > previousData.fuelQuantity.Pounds) {
return [false]
}

return [
Acars.NumberOverPercent(
data.fuelQuantity.Pounds,
previousData.fuelQuantity.Pounds,
10,
),
`Fuel Refilled: Current: ${data.fuelQuantity.Pounds}, previous=${previousData.fuelQuantity.Pounds}`,
]
}
}
32 changes: 32 additions & 0 deletions src/rules/hard_landing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { PirepState } from '../defs'
import { Meta, Rule, RuleValue } from '../types/rule'
import { Pirep, Telemetry } from '../types/types'

export default class HandLandings implements Rule {
meta: Meta = {
id: 'HARD_LANDING',
name: 'Hard Landing',
enabled: true, // Default, will change depending on airline config
message: 'Hard Landing',
states: [PirepState.Final, PirepState.Landed],
repeatable: false,
cooldown: 60,
max_count: 3,
points: -1,
parameter: 300, // default, gets overwritten from remote
}

violated(pirep: Pirep, data: Telemetry, previousData?: Telemetry): RuleValue {
const absRate = Math.abs(pirep.landingRate.FeetPerMinute)
const absParam = Math.abs(this.meta.parameter!)
if (absRate < absParam) {
return [false]
}

console.log(
`Hard landing violation, rate=${absRate}, threshold=${absParam}`,
)

return [true]
}
}
40 changes: 40 additions & 0 deletions src/rules/lights_off_during_taxi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Determine if the beacon lights are on while the aircraft is in motio
*/
import { AircraftFeature, PirepState } from '../defs'
import { Meta, Rule, RuleValue } from '../types/rule'
import { Pirep, Telemetry } from '../types/types'

export default class LightsOffDuringTaxi implements Rule {
meta: Meta = {
id: 'LAND_LIGHTS_OFF_TAXI',
name: 'Landing lights must be off during pushback or taxi',
enabled: true,
message: 'Landing lights must be off during pushback or taxi',
states: [PirepState.TaxiOut, PirepState.Pushback, PirepState.TaxiIn],
repeatable: false,
cooldown: 60,
max_count: 3,
points: -1,
delay_time: 5000,
}

violated(pirep: Pirep, data: Telemetry, previousData?: Telemetry): RuleValue {
if (!Acars.IsFeatureEnabled(AircraftFeature.LandingLights)) {
return [false]
}

return Acars.ViolatedAfterDelay(
this.meta.id,
this.meta.delay_time,
(): RuleValue => {
// Ignore landing lights being turned on
if (data.approachingRunway != null || data.runway != null) {
return [false]
}

return [data.landingLights]
},
)
}
}
44 changes: 44 additions & 0 deletions src/rules/lights_over_10k.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Determine if the beacon lights are on while the aircraft is in motio
*/
import { AircraftFeature, PirepState } from '../defs'
import { Meta, Rule, RuleValue } from '../types/rule'
import { Pirep, Telemetry } from '../types/types'

export default class LightsOver10K implements Rule {
meta: Meta = {
id: 'LAND_LIGHTS_OVER_10K',
name: 'Landing lights must be off above ',
enabled: true,
message: 'Landing lights must be off above ',
states: [],
repeatable: false,
cooldown: 60,
max_count: 3,
points: -1,
delay_time: 5000,
}

violated(pirep: Pirep, data: Telemetry, previousData?: Telemetry): RuleValue {
if (!Acars.IsFeatureEnabled(AircraftFeature.LandingLights)) {
return [false]
}

if (data.onGround) {
return [false]
}

return Acars.ViolatedAfterDelay(
this.meta.id,
this.meta.delay_time,
(): RuleValue => {
// Ignore landing lights being turned on
const violated =
data.landingLights &&
data.planeAltitude.Feet > this.meta.parameter! + 500

return [violated, this.meta.message + this.meta.parameter!]
},
)
}
}
Loading

0 comments on commit ebb3d25

Please sign in to comment.