@@ -207,6 +207,7 @@ if Code.ensure_loaded?(Circuits.UART) do
207207 answer_invoke_id: non_neg_integer ( ) | nil ,
208208 send_queue: :queue . queue ( send_item ( ) ) ,
209209 send_timer: :timer . tref ( ) | nil ,
210+ disable_maintenance_pfm: boolean ( ) ,
210211 disable_token_passing: boolean ( ) ,
211212 autobaud_baudrate: non_neg_integer ( ) | nil ,
212213 autobaud_baudrates_pending: [ non_neg_integer ( ) ] | nil ,
@@ -244,6 +245,7 @@ if Code.ensure_loaded?(Circuits.UART) do
244245 :answer_invoke_id ,
245246 :send_queue ,
246247 :send_timer ,
248+ :disable_maintenance_pfm ,
247249 :disable_token_passing ,
248250 :autobaud_baudrate ,
249251 :autobaud_baudrates_pending ,
@@ -865,11 +867,7 @@ if Code.ensure_loaded?(Circuits.UART) do
865867
866868 There are no options at this time.
867869 """
868- @ spec reply_postponed (
869- portal :: TransportBehaviour . portal ( ) ,
870- destination :: source_address ( ) ,
871- opts :: Keyword . t ( )
872- ) ::
870+ @ spec reply_postponed ( TransportBehaviour . portal ( ) , source_address ( ) , Keyword . t ( ) ) ::
873871 :ok
874872 | { :error , term ( ) }
875873 | { :error , :slave_mode }
@@ -881,6 +879,20 @@ if Code.ensure_loaded?(Circuits.UART) do
881879 GenServer . call ( portal , { :reply_postponed , destination , opts } , @ call_timeout )
882880 end
883881
882+ @ doc """
883+ Enables or disables maintenance POLL_FOR_MASTER in the case the successor node is known.
884+ If the successor node is unknown, POLL_FOR_MASTER will be regardless done.
885+
886+ This function is only for development and testing purpose. It must not be used in production.
887+ Periodic maintenance polling for masters is required to find new nodes in between this node
888+ and the next current successor node. Nodes may come up and go down any time, which
889+ the BACnet specification accounts for and thus includes a POLL_FOR_MASTER mechanism.
890+ """
891+ @ spec set_maintenance_pfm ( TransportBehaviour . transport ( ) , boolean ( ) ) :: :ok
892+ def set_maintenance_pfm ( transport , state ) when is_server ( transport ) and is_boolean ( state ) do
893+ GenServer . call ( transport , { :disable_maintenance_pfm , not state } )
894+ end
895+
884896 @ doc false
885897 def init ( { callback , opts } ) do
886898 new_opts =
@@ -946,6 +958,7 @@ if Code.ensure_loaded?(Circuits.UART) do
946958 answer_invoke_id: nil ,
947959 send_queue: :queue . new ( ) ,
948960 send_timer: nil ,
961+ disable_maintenance_pfm: false ,
949962 disable_token_passing: false ,
950963 autobaud_baudrate: nil ,
951964 autobaud_baudrates_pending: nil ,
@@ -1296,6 +1309,33 @@ if Code.ensure_loaded?(Circuits.UART) do
12961309 end
12971310 end
12981311
1312+ defp do_handle_continue (
1313+ :done_with_token ,
1314+ % State {
1315+ local_address: local_addr ,
1316+ disable_maintenance_pfm: true ,
1317+ disable_token_passing: false ,
1318+ state_machine: % { ns: ns , ps: ps , token_count: tokens } = state_machine
1319+ } =
1320+ state
1321+ )
1322+ when local_addr < @ min_slave_addr and
1323+ ns != rem ( ps + 1 , state . opts . max_master_address + 1 ) and
1324+ tokens >= @ param_n_poll - 1 do
1325+ log_debug ( fn ->
1326+ "BacMstpTransport: Reached state DONE_WITH_TOKEN and skipping maintenance POLL_FOR_MASTER, " <>
1327+ "skipping to USE_TOKEN instead (maintenance PFM disabled)"
1328+ end )
1329+
1330+ new_state = % {
1331+ state
1332+ | state_machine: % { state_machine | frame_count: 0 , token_count: 0 } ,
1333+ transport_state: :use_token
1334+ }
1335+
1336+ { :noreply , new_state , { :continue , :use_token } }
1337+ end
1338+
12991339 # If token passing is disabled, do not engage maintenance PFM, instead:
13001340 # - If successor known, pass it to the successor
13011341 # - If successor unknown, drop the token
@@ -1752,6 +1792,16 @@ if Code.ensure_loaded?(Circuits.UART) do
17521792 { :reply , { :error , :slave_mode } , state }
17531793 end
17541794
1795+ defp do_handle_call ( { :disable_maintenance_pfm , pfm_state } , _from , % State { } = state )
1796+ when is_boolean ( pfm_state ) do
1797+ log_debug ( fn ->
1798+ "BacMstpTransport: Received disable_maintenance_pfm request with " <>
1799+ "value #{ pfm_state } "
1800+ end )
1801+
1802+ { :reply , :ok , % { state | disable_maintenance_pfm: pfm_state } }
1803+ end
1804+
17551805 defp do_handle_call ( _call , _from , state ) do
17561806 { :noreply , state }
17571807 end
0 commit comments