Skip to content

Commit

Permalink
#248 Remove broken ACCELEROMETER_VALUE and add gauge value controls (#…
Browse files Browse the repository at this point in the history
…261)

Adds a control for defining gauge values, which are used in some older aircraft.
  • Loading branch information
charliefoxtwo authored Sep 29, 2023
1 parent b7dca05 commit 1c96ee2
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 193 deletions.
64 changes: 23 additions & 41 deletions Scripts/DCS-BIOS/doc/json/P-51D.json

Large diffs are not rendered by default.

64 changes: 23 additions & 41 deletions Scripts/DCS-BIOS/doc/json/P-51D.jsonp

Large diffs are not rendered by default.

7 changes: 0 additions & 7 deletions Scripts/DCS-BIOS/lib/meta_files/DCS_API_defs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,6 @@ CockpitPage = ""
--- @return string[]
function list_cockpit_params() end

--- @func Maps value to from input_range to output_range
--- @param argument_value number
--- @param input_range table<number>
--- @param output_range table<number>
--- @return number
function ValueConvert(argument_value, input_range, output_range) end

--- @func Returns altitude above sea level
--- @return number
function LoGetAltitudeAboveSeaLevel() end
Expand Down
45 changes: 41 additions & 4 deletions Scripts/DCS-BIOS/lib/modules/Module.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,36 @@ function Module:new(name, baseAddress, acftList)
return o
end

--- Reserves space in the memory map for an integer with the specified max value
---@param max_value integer the max value of the integer to reserve space for
function Module:reserveIntValue(max_value)
self:allocateInt(max_value)
end

--- Defines a gauge from floating-point data with limits. This generally is not used in any new modules and is used in existing modules to provide the integer output of a gauge
--- @param identifier string the unique identifier for the control
--- @param arg_number integer the dcs argument number
--- @param output_range number[] a length-2 array with the lower and upper bounds of the output data - lower bound must be greater than or equal to zero
--- @param category string the category in which the control should appear
--- @param description string additional information about the control
--- @return Control control the control which was added to the module
function Module:defineGaugeValue(identifier, arg_number, output_range, category, description)
assert(output_range[1] >= 0)

local max_value = 65535
local alloc = self:allocateInt(max_value)
self:addExportHook(function(dev0)
alloc:setValue(Module.valueConvert(dev0:get_argument_value(arg_number), { 0, 1 }, output_range))
end)

local control = Control:new(category, ControlType.metadata, identifier, description, {}, {
IntegerOutput:new(alloc, Suffix.none, description),
})
self:addControl(control)

return control
end

--- Defines a gauge from floating-point data with limits
--- @param identifier string the unique identifier for the control
--- @param arg_number integer the dcs argument number
Expand All @@ -54,15 +84,12 @@ end
--- @param description string additional information about the control
--- @return Control control the control which was added to the module
function Module:defineFloat(identifier, arg_number, limits, category, description)
local intervalLength = limits[2] - limits[1]
local max_value = 65535
local alloc = self:allocateInt(max_value)

self:addExportHook(function(dev0)
alloc:setValue(((dev0:get_argument_value(arg_number) - limits[1]) / intervalLength) * max_value)
alloc:setValue(Module.valueConvert(dev0:get_argument_value(arg_number), limits, { 0, max_value }))
end)

-- todo: almost identical to below for allocating an int, just different descriptions?
local control = Control:new(category, ControlType.analog_gauge, identifier, description, {}, {
IntegerOutput:new(alloc, Suffix.none, "gauge position"),
})
Expand Down Expand Up @@ -745,4 +772,14 @@ function Module.round(num)
return num >= 0 and math.floor(num + 0.5) or math.ceil(num - 0.5)
end

--- @func Maps value to from input_range to output_range
--- @param argument_value number the number to map
--- @param input_range number[] a length-2 array of the range of the input value
--- @param output_range number[] a length-2 array of the range the value should be mapped to
--- @return number
function Module.valueConvert(argument_value, input_range, output_range)
local slope = 1.0 * (output_range[2] - output_range[1]) / (input_range[2] - input_range[1])
return output_range[1] + slope * (argument_value - input_range[1])
end

return Module
114 changes: 19 additions & 95 deletions Scripts/DCS-BIOS/lib/modules/aircraft_modules/P-51D.lua
Original file line number Diff line number Diff line change
Expand Up @@ -169,119 +169,43 @@ P_51D:defineBitFromDrawArgument("EXT_RECOC_LIGHT_YE", 202, "External Aircraft Mo

--[[--Gauge Values--]]
--
local function getAirspeed()
local returnValue = (GetDevice(0):get_argument_value(11)) * 1000
return returnValue
end
P_51D:defineIntegerFromGetter("AIRSPEED_MPH_VALUE", getAirspeed, 65000, "Gauge Values", "Airspeed MPH")
P_51D:defineGaugeValue("AIRSPEED_MPH_VALUE", 11, { 0, 1000 }, "Gauge Values", "Airspeed MPH")

local function getAltitude()
local returnValue = (GetDevice(0):get_argument_value(96)) * 100000
return returnValue
end
P_51D:defineIntegerFromGetter("ALTIMETER_VALUE", getAltitude, 65000, "Gauge Values", "Altimeter")
P_51D:defineGaugeValue("ALTIMETER_VALUE", 96, { 0, 100000 }, "Gauge Values", "Altimeter")

local function getEngineRPM()
local returnValue = (GetDevice(0):get_argument_value(23)) * 4500
return returnValue
end
P_51D:defineIntegerFromGetter("ENGINE_RPM_VALUE", getEngineRPM, 65000, "Gauge Values", "Engine RPM Value")
P_51D:defineGaugeValue("ENGINE_RPM_VALUE", 23, { 0, 4500 }, "Gauge Values", "Engine RPM Value")

local function getGyro()
local returnValue = (GetDevice(0):get_argument_value(12)) * 360
return returnValue
end
P_51D:defineIntegerFromGetter("DIRECTIONAL_GYRO_VALUE", getGyro, 65000, "Gauge Values", "Directional Gyro")
P_51D:defineGaugeValue("DIRECTIONAL_GYRO_VALUE", 12, { 0, 360 }, "Gauge Values", "Directional Gyro")

local function getHDG()
local returnValue = (GetDevice(0):get_argument_value(1)) * 360
return returnValue
end
P_51D:defineIntegerFromGetter("HEADING_VALUE", getHDG, 65000, "Gauge Values", "Remote Compass Heading")
P_51D:defineGaugeValue("HEADING_VALUE", 1, { 0, 360 }, "Gauge Values", "Remote Compass Heading")

local function getCRS()
local returnValue = (GetDevice(0):get_argument_value(2)) * 360
return returnValue
end
P_51D:defineIntegerFromGetter("COURSE_VALUE", getCRS, 65000, "Gauge Values", "Remote Compass Course")
P_51D:defineGaugeValue("COURSE_VALUE", 2, { 0, 360 }, "Gauge Values", "Remote Compass Course")

local function getFuelPres()
local returnValue = (GetDevice(0):get_argument_value(32)) * 25
return returnValue
end
P_51D:defineIntegerFromGetter("FUEL_PRESSURE_VALUE", getFuelPres, 65000, "Gauge Values", "Fuel Pressure")
P_51D:defineGaugeValue("FUEL_PRESSURE_VALUE", 32, { 0, 25 }, "Gauge Values", "Fuel Pressure")

local function getHydPres()
local returnValue = (GetDevice(0):get_argument_value(78)) * 2000
return returnValue
end
P_51D:defineIntegerFromGetter("HYDRAULIC_PRESSURE_VALUE", getHydPres, 65000, "Gauge Values", "Hydraulic Pressure")
P_51D:defineGaugeValue("HYDRAULIC_PRESSURE_VALUE", 78, { 0, 2000 }, "Gauge Values", "Hydraulic Pressure")

local function getManifoldPres()
local returnValue = (GetDevice(0):get_argument_value(10)) * 65 + 10
return returnValue
end
P_51D:defineIntegerFromGetter("MANIFOLD_PRESSURE_VALUE", getManifoldPres, 65000, "Gauge Values", "Manifold Pressure")
P_51D:defineGaugeValue("MANIFOLD_PRESSURE_VALUE", 10, { 10, 75 }, "Gauge Values", "Manifold Pressure")

local function getVacuum()
local returnValue = (GetDevice(0):get_argument_value(9)) * 100
return returnValue
end
P_51D:defineIntegerFromGetter("VACUUM_SUCTION_VALUE", getVacuum, 65000, "Gauge Values", "Vacuum Suction read as X.X or XX.X")
P_51D:defineGaugeValue("VACUUM_SUCTION_VALUE", 9, { 0, 100 }, "Gauge Values", "Vacuum Suction read as X.X or XX.X")

local function getOilTemp()
local returnValue = (GetDevice(0):get_argument_value(30)) * 100
return returnValue
end
P_51D:defineIntegerFromGetter("OIL_TEMPERATURE_VALUE", getOilTemp, 65000, "Gauge Values", "Oil Temperature")
P_51D:defineGaugeValue("OIL_TEMPERATURE_VALUE", 30, { 0, 100 }, "Gauge Values", "Oil Temperature")

local function getOilPres()
local returnValue = (GetDevice(0):get_argument_value(31)) * 200
return returnValue
end
P_51D:defineIntegerFromGetter("OIL_PRESSURE_VALUE", getOilPres, 65000, "Gauge Values", "Oil Pressure")
P_51D:defineGaugeValue("OIL_PRESSURE_VALUE", 31, { 0, 200 }, "Gauge Values", "Oil Pressure")

local function getAmps()
local returnValue = (GetDevice(0):get_argument_value(101)) * 150
return returnValue
end
P_51D:defineIntegerFromGetter("AMMETER_VALUE", getAmps, 65000, "Gauge Values", "Ammeter")
P_51D:defineGaugeValue("AMMETER_VALUE", 101, { 0, 150 }, "Gauge Values", "Ammeter")

local function getOxygen()
local returnValue = (GetDevice(0):get_argument_value(34)) * 500
return returnValue
end
P_51D:defineIntegerFromGetter("OXYGEN_PRESSURE_VALUE", getOxygen, 65000, "Gauge Values", "Oxygen Pressure")
P_51D:defineGaugeValue("OXYGEN_PRESSURE_VALUE", 34, { 0, 500 }, "Gauge Values", "Oxygen Pressure")

local function getLeftFuel()
local returnValue = (GetDevice(0):get_argument_value(155)) * 92
return returnValue
end
P_51D:defineIntegerFromGetter("LEFT_FUEL_TANK_VALUE", getLeftFuel, 65000, "Gauge Values", "Left Fuel Tank Gallons")
P_51D:defineGaugeValue("LEFT_FUEL_TANK_VALUE", 155, { 0, 92 }, "Gauge Values", "Left Fuel Tank Gallons")

local function getRightFuel()
local returnValue = (GetDevice(0):get_argument_value(156)) * 92
return returnValue
end
P_51D:defineIntegerFromGetter("RIGHT_FUEL_TANK_VALUE", getRightFuel, 65000, "Gauge Values", "Right Fuel Tank Gallons")
P_51D:defineGaugeValue("RIGHT_FUEL_TANK_VALUE", 156, { 0, 92 }, "Gauge Values", "Right Fuel Tank Gallons")

local function getFuseFuel()
local returnValue = (GetDevice(0):get_argument_value(160)) * 85
return returnValue
end
P_51D:defineIntegerFromGetter("FUSELAGE_FUEL_TANK_VALUE", getFuseFuel, 65000, "Gauge Values", "Fuselage Fuel Tank Gallons")
P_51D:defineGaugeValue("FUSELAGE_FUEL_TANK_VALUE", 160, { 0, 85 }, "Gauge Values", "Fuselage Fuel Tank Gallons")

local function getBaro()
local returnValue = (GetDevice(0):get_argument_value(97)) * 290 + 2810
return returnValue
end
P_51D:defineIntegerFromGetter("BAROMETRIC_PRESSURE_VALUE", getBaro, 65000, "Gauge Values", "Barometric Pressure")
P_51D:defineGaugeValue("BAROMETRIC_PRESSURE_VALUE", 97, { 2810, 3100 }, "Gauge Values", "Barometric Pressure")

local function getAccel()
local returnValue = (GetDevice(0):get_argument_value(175)) * 17 - 5
return returnValue
end
P_51D:defineIntegerFromGetter("ACCELEROMETER_VALUE", getAccel, 65000, "Gauge Values", "Accelerometer")
P_51D:reserveIntValue(65535) -- removed non-functional ACCELEROMETER_VALUE (#248)

P_51D:defineIndicatorLight("WINDSHIELD_OIL_L", 412, "Damage", "Windshield Oil Splashes (black)")
P_51D:defineFloat("WINDSHIELD_CRACKS", 413, { 0, 1 }, "Damage", "Windshield Crack Holes")
Expand Down
6 changes: 1 addition & 5 deletions Scripts/DCS-BIOS/test/ModuleTest.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ TestModule = {}
local moduleName = "MyModule"
local moduleAddress = 0x4200

function ValueConvert(value, input_range, output_range)
local slope = 1.0 * (output_range[2] - output_range[1]) / (input_range[2] - input_range[1])
return output_range[1] + slope * (value - input_range[1])
end

function TestModule:setUp()
self.module = Module:new(moduleName, moduleAddress, {})
end
Expand All @@ -33,6 +28,7 @@ function LoGetAircraftDrawArgumentValue()
return GetDevice().value
end

require("GaugeValueTest")
require("FloatTest")
require("IndicatorLightTest")
require("GatedIndicatorLightTest")
Expand Down
84 changes: 84 additions & 0 deletions Scripts/DCS-BIOS/test/controls/GaugeValueTest.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
local ControlType = require("ControlType")
local MockDevice = require("MockDevice")
local Module = require("Module")
local OutputType = require("OutputType")
local Suffix = require("Suffix")

local lu = require("luaunit")

--- @class TestGaugeValue
--- @field module Module
TestGaugeValue = {}
local moduleName = "MyModule"
local moduleAddress = 0x4200

function TestGaugeValue:setUp()
self.module = Module:new(moduleName, moduleAddress, {})
end

local id = "MY_GAUGE_VALUE"
local arg_number = 1
local category = "Gauge Values"
local description = "This is a gauge value"

function TestGaugeValue:testAddGaugeValue()
local limits = { 0, 1 }

local control = self.module:defineGaugeValue(id, arg_number, limits, category, description)

lu.assertEquals(control, self.module.documentation[category][id])
lu.assertEquals(control.control_type, ControlType.metadata)
lu.assertEquals(control.category, category)
lu.assertEquals(control.description, description)
lu.assertEquals(control.identifier, id)
lu.assertIsNil(control.physical_variant)
lu.assertIsNil(control.api_variant)

lu.assertEquals(#control.inputs, 0)

lu.assertEquals(#control.outputs, 1)
local output = control.outputs[1] --[[@as IntegerOutput]]
lu.assertEquals(output.type, OutputType.integer)
lu.assertEquals(output.max_value, 65535)
lu.assertEquals(output.suffix, Suffix.none)
lu.assertEquals(output.description, description)
lu.assertEquals(output.address, moduleAddress) -- first control, should be plenty of room, no need to move the address
end

function TestGaugeValue:testGaugeValueZeroMinValue()
local limits = { 0, 500 }

self.module:defineGaugeValue(id, arg_number, limits, category, description)

local export_hook = self.module.exportHooks[1]

local alloc = self.module.memoryMap.entries[moduleAddress].allocations[1]

export_hook(MockDevice:new(0))
lu.assertEquals(alloc.value, 0)

export_hook(MockDevice:new(0.5))
lu.assertEquals(alloc.value, 250)

export_hook(MockDevice:new(1))
lu.assertEquals(alloc.value, 500)
end

function TestGaugeValue:testGaugeValuePositiveMinValue()
local limits = { 10, 75 }

self.module:defineGaugeValue(id, arg_number, limits, category, description)

local export_hook = self.module.exportHooks[1]

local alloc = self.module.memoryMap.entries[moduleAddress].allocations[1]

export_hook(MockDevice:new(0))
lu.assertEquals(alloc.value, 10)

export_hook(MockDevice:new(0.5))
lu.assertEquals(alloc.value, 42)

export_hook(MockDevice:new(1))
lu.assertEquals(alloc.value, 75)
end

0 comments on commit 1c96ee2

Please sign in to comment.