From 3ceb1444de57f63c16aba0ed952bd7bd68cfb4ec Mon Sep 17 00:00:00 2001 From: Karolis Petrauskas Date: Fri, 20 Feb 2026 17:33:57 +0200 Subject: [PATCH] Consider inf/nan when validating float ranges. --- .../protocol/object_types/analog_input.ex | 10 ++------ .../protocol/object_types/analog_output.ex | 19 +++----------- .../protocol/object_types/analog_value.ex | 19 +++----------- lib/bacnet/protocol/utility.ex | 25 +++++++++++++++++++ 4 files changed, 33 insertions(+), 40 deletions(-) diff --git a/lib/bacnet/protocol/object_types/analog_input.ex b/lib/bacnet/protocol/object_types/analog_input.ex index cda7b382..8d04c323 100644 --- a/lib/bacnet/protocol/object_types/analog_input.ex +++ b/lib/bacnet/protocol/object_types/analog_input.ex @@ -11,6 +11,7 @@ defmodule BACnet.Protocol.ObjectTypes.AnalogInput do # TODO: Docs alias BACnet.Protocol.Constants + alias BACnet.Protocol.Utility require Constants use BACnet.Protocol.ObjectsMacro @@ -39,14 +40,7 @@ defmodule BACnet.Protocol.ObjectTypes.AnalogInput do field(:present_value, float(), required: true, default: 0.0, - validator_fun: fn - value, %{min_present_value: min, max_present_value: max} - when not is_nil(min) and not is_nil(max) -> - min <= value and value <= max - - _value, _obj -> - true - end + validator_fun: &Utility.float_validator_fun/2 ) field(:reliability, Constants.reliability(), diff --git a/lib/bacnet/protocol/object_types/analog_output.ex b/lib/bacnet/protocol/object_types/analog_output.ex index c36f15a3..05063519 100644 --- a/lib/bacnet/protocol/object_types/analog_output.ex +++ b/lib/bacnet/protocol/object_types/analog_output.ex @@ -12,6 +12,7 @@ defmodule BACnet.Protocol.ObjectTypes.AnalogOutput do alias BACnet.Protocol.Constants alias BACnet.Protocol.PriorityArray + alias BACnet.Protocol.Utility require Constants use BACnet.Protocol.ObjectsMacro @@ -47,14 +48,7 @@ defmodule BACnet.Protocol.ObjectTypes.AnalogOutput do field(:present_value, float(), required: true, default: 0.0, - validator_fun: fn - value, %{min_present_value: min, max_present_value: max} - when not is_nil(min) and not is_nil(max) -> - min <= value and value <= max - - _value, _obj -> - true - end + validator_fun: &Utility.float_validator_fun/2 ) field(:priority_array, PriorityArray.t(float()), required: true, readonly: true) @@ -62,14 +56,7 @@ defmodule BACnet.Protocol.ObjectTypes.AnalogOutput do field(:relinquish_default, float(), required: true, default: 0.0, - validator_fun: fn - value, %{min_present_value: min, max_present_value: max} - when not is_nil(min) and not is_nil(max) -> - min <= value and value <= max - - _value, _obj -> - true - end + validator_fun: &Utility.float_validator_fun/2 ) field(:reliability, Constants.reliability(), diff --git a/lib/bacnet/protocol/object_types/analog_value.ex b/lib/bacnet/protocol/object_types/analog_value.ex index aee51544..704a208a 100644 --- a/lib/bacnet/protocol/object_types/analog_value.ex +++ b/lib/bacnet/protocol/object_types/analog_value.ex @@ -13,6 +13,7 @@ defmodule BACnet.Protocol.ObjectTypes.AnalogValue do alias BACnet.Protocol.Constants alias BACnet.Protocol.PriorityArray + alias BACnet.Protocol.Utility require Constants use BACnet.Protocol.ObjectsMacro @@ -48,28 +49,14 @@ defmodule BACnet.Protocol.ObjectTypes.AnalogValue do field(:present_value, float(), required: true, default: 0.0, - validator_fun: fn - value, %{min_present_value: min, max_present_value: max} - when not is_nil(min) and not is_nil(max) -> - min <= value and value <= max - - _value, _obj -> - true - end + validator_fun: &Utility.float_validator_fun/2 ) field(:priority_array, PriorityArray.t(float()), readonly: true) field(:relinquish_default, float(), default: 0.0, - validator_fun: fn - value, %{min_present_value: min, max_present_value: max} - when not is_nil(min) and not is_nil(max) -> - min <= value and value <= max - - _value, _obj -> - true - end + validator_fun: &Utility.float_validator_fun/2 ) field(:reliability, Constants.reliability(), diff --git a/lib/bacnet/protocol/utility.ex b/lib/bacnet/protocol/utility.ex index 8acb61dd..620d899c 100644 --- a/lib/bacnet/protocol/utility.ex +++ b/lib/bacnet/protocol/utility.ex @@ -100,4 +100,29 @@ defmodule BACnet.Protocol.Utility do end end end + + def float_validator_fun(value, %{min_present_value: min, max_present_value: max}) + when not is_nil(min) and not is_nil(max) do + min_ok = + case min do + :NaN -> true + :inf -> false + :infn -> true + min when is_float(min) -> min <= value + end + + max_ok = + case max do + :NaN -> true + :inf -> true + :infn -> false + max when is_float(max) -> value <= max + end + + min_ok and max_ok + end + + def float_validator_fun(_value, _obj) do + true + end end