@@ -253,8 +253,7 @@ defmodule BACnet.Stack.Client do
253253 disable_app_timeout: boolean ( ) ,
254254 disable_invoke_id_management: boolean ( ) ,
255255 npci_source: NpciTarget . t ( ) | nil ,
256- segmented_rcv_window_overwrite: boolean ( ) ,
257- supervisor_mod: module ( )
256+ segmented_rcv_window_overwrite: boolean ( )
258257 }
259258 }
260259
@@ -380,11 +379,56 @@ defmodule BACnet.Stack.Client do
380379 :transport
381380 ] )
382381
383- validate_start_link_opts ( opts2 )
382+ validate_start_link_opts ( opts2 , "start_link/1" )
384383
385384 GenServer . start_link ( __MODULE__ , Map . new ( opts2 ) , genserver_opts )
386385 end
387386
387+ @ doc """
388+ Configure the client.
389+
390+ Only some of the available `t:start_options/0` can be configured,
391+ unsupported options can only be changed by re-starting the client completely.
392+
393+ The following options are supported:
394+ - `apdu_retries`
395+ - `apdu_timeout`
396+ - `disable_app_timeout` (note that current active timers will NOT be cancelled)
397+ - `npci_source`
398+ - `segmented_rcv_window_overwrite`
399+
400+ For a description of each option, see `start_link/1`.
401+ """
402+ @ spec configure ( server ( ) , start_options ( ) ) :: :ok
403+ def configure ( server , opts ) when is_server ( server ) and is_list ( opts ) do
404+ unless Keyword . keyword? ( opts ) do
405+ raise ArgumentError ,
406+ "configure/2 expected opts to be a keyword list, " <>
407+ "got: #{ inspect ( opts ) } "
408+ end
409+
410+ validate_start_link_opts ( opts , "configure/2" , true )
411+
412+ Enum . each ( opts , fn
413+ # Supported options
414+ { key , _val }
415+ when key in [
416+ :apdu_retries ,
417+ :apdu_timeout ,
418+ :disable_app_timeout ,
419+ :npci_source ,
420+ :segmented_rcv_window_overwrite
421+ ] ->
422+ true
423+
424+ { key , _val } ->
425+ raise ArgumentError ,
426+ "configure/2 does not support option " <> inspect ( key )
427+ end )
428+
429+ GenServer . call ( server , { :configure , Map . new ( opts ) } )
430+ end
431+
388432 @ doc """
389433 Add a source to the per-source APDU timeouts map. This is only used for receiving.
390434
@@ -628,6 +672,11 @@ defmodule BACnet.Stack.Client do
628672 end
629673
630674 @ doc false
675+ def handle_call ( { :configure , % { } = opts } , _from , % State { } = state ) do
676+ new_state = % { state | opts: Map . merge ( state . opts , opts ) }
677+ { :reply , :ok , new_state }
678+ end
679+
631680 def handle_call (
632681 { :add_apdu_timeout , source_address , device_id , timeout } ,
633682 _from ,
@@ -2247,7 +2296,8 @@ defmodule BACnet.Stack.Client do
22472296 defp kw_put_new ( kw , key , val ) , do: Keyword . put_new ( kw , key , val )
22482297
22492298 # credo:disable-for-lines:50 Credo.Check.Refactor.CyclomaticComplexity
2250- defp validate_start_link_opts ( opts ) do
2299+ defp validate_start_link_opts ( opts , mfa , skip_check \\ false )
2300+ when is_binary ( mfa ) and is_boolean ( skip_check ) do
22512301 case opts [ :apdu_retries ] do
22522302 nil ->
22532303 :ok
@@ -2257,7 +2307,8 @@ defmodule BACnet.Stack.Client do
22572307
22582308 term ->
22592309 raise ArgumentError ,
2260- "start_link/1 expected apdu_retries to be a non negative integer, " <>
2310+ mfa <>
2311+ " expected apdu_retries to be a non negative integer, " <>
22612312 "got: #{ inspect ( term ) } "
22622313 end
22632314
@@ -2270,7 +2321,8 @@ defmodule BACnet.Stack.Client do
22702321
22712322 term ->
22722323 raise ArgumentError ,
2273- "start_link/1 expected apdu_timeout to be a positive integer, " <>
2324+ mfa <>
2325+ " expected apdu_timeout to be a positive integer, " <>
22742326 "got: #{ inspect ( term ) } "
22752327 end
22762328
@@ -2283,7 +2335,8 @@ defmodule BACnet.Stack.Client do
22832335
22842336 term ->
22852337 raise ArgumentError ,
2286- "start_link/1 expected disable_app_timeout to be a boolean, " <>
2338+ mfa <>
2339+ " expected disable_app_timeout to be a boolean, " <>
22872340 "got: #{ inspect ( term ) } "
22882341 end
22892342
@@ -2296,7 +2349,8 @@ defmodule BACnet.Stack.Client do
22962349
22972350 term ->
22982351 raise ArgumentError ,
2299- "start_link/1 expected disable_invoke_id_management to be a boolean, " <>
2352+ mfa <>
2353+ " expected disable_invoke_id_management to be a boolean, " <>
23002354 "got: #{ inspect ( term ) } "
23012355 end
23022356
@@ -2323,13 +2377,15 @@ defmodule BACnet.Stack.Client do
23232377 ( is_tuple ( & 1 ) and tuple_size ( & 1 ) == 2 ) )
23242378 ) do
23252379 raise ArgumentError ,
2326- "start_link/1 expected notification_receiver to be a Process destination or " <>
2380+ mfa <>
2381+ " expected notification_receiver to be a Process destination or " <>
23272382 "list of Process destinations, got: #{ inspect ( term ) } "
23282383 end
23292384
23302385 term ->
23312386 raise ArgumentError ,
2332- "start_link/1 expected notification_receiver to be a Process destination or " <>
2387+ mfa <>
2388+ " expected notification_receiver to be a Process destination or " <>
23332389 "list of Process destinations, got: #{ inspect ( term ) } "
23342390 end
23352391
@@ -2342,7 +2398,8 @@ defmodule BACnet.Stack.Client do
23422398
23432399 term ->
23442400 raise ArgumentError ,
2345- "start_link/1 expected npci_source to be a NpciTarget, " <>
2401+ mfa <>
2402+ " expected npci_source to be a NpciTarget, " <>
23462403 "got: #{ inspect ( term ) } "
23472404 end
23482405
@@ -2361,7 +2418,8 @@ defmodule BACnet.Stack.Client do
23612418
23622419 term ->
23632420 raise ArgumentError ,
2364- "start_link/1 expected segmentator to be a GenServer name, " <>
2421+ mfa <>
2422+ " expected segmentator to be a GenServer name, " <>
23652423 "got: #{ inspect ( term ) } "
23662424 end
23672425
@@ -2380,7 +2438,8 @@ defmodule BACnet.Stack.Client do
23802438
23812439 term ->
23822440 raise ArgumentError ,
2383- "start_link/1 expected segments_store to be a GenServer name, " <>
2441+ mfa <>
2442+ " expected segments_store to be a GenServer name, " <>
23842443 "got: #{ inspect ( term ) } "
23852444 end
23862445
@@ -2393,7 +2452,8 @@ defmodule BACnet.Stack.Client do
23932452
23942453 term ->
23952454 raise ArgumentError ,
2396- "start_link/1 expected segmented_rcv_window_overwrite to be a boolean, " <>
2455+ mfa <>
2456+ " expected segmented_rcv_window_overwrite to be a boolean, " <>
23972457 "got: #{ inspect ( term ) } "
23982458 end
23992459
@@ -2420,29 +2480,32 @@ defmodule BACnet.Stack.Client do
24202480
24212481 term ->
24222482 raise ArgumentError ,
2423- "start_link/1 expected transport to be a tuple of module name " <>
2483+ mfa <>
2484+ " expected transport to be a tuple of module name " <>
24242485 "and TransportBehaviour.transport(), got: #{ inspect ( term ) } "
24252486 end
24262487
2427- # Unwrap the transport module name
2428- { transport_mod , _pid } =
2429- case transport do
2430- { mod , pid } -> { mod , pid }
2431- mod -> { mod , nil }
2432- end
2488+ if not skip_check do
2489+ # Unwrap the transport module name
2490+ { transport_mod , _pid } =
2491+ case transport do
2492+ { mod , pid } -> { mod , pid }
2493+ mod -> { mod , nil }
2494+ end
24332495
2434- unless Code . ensure_loaded? ( transport_mod ) do
2435- raise ArgumentError , "Given transport module #{ inspect ( transport_mod ) } is not loaded"
2436- end
2496+ unless Code . ensure_loaded? ( transport_mod ) do
2497+ raise ArgumentError , "Given transport module #{ inspect ( transport_mod ) } is not loaded"
2498+ end
24372499
2438- unless Enum . any? ( transport_mod . __info__ ( :attributes ) , fn
2439- { :behaviour , TransportBehaviour } -> true
2440- { :behaviour , [ TransportBehaviour ] } -> true
2441- _else -> false
2442- end ) do
2443- raise ArgumentError ,
2444- "Given transport module #{ inspect ( transport_mod ) } does not " <>
2445- "implement the BACnet transport behaviour"
2500+ unless Enum . any? ( transport_mod . __info__ ( :attributes ) , fn
2501+ { :behaviour , TransportBehaviour } -> true
2502+ { :behaviour , [ TransportBehaviour ] } -> true
2503+ _else -> false
2504+ end ) do
2505+ raise ArgumentError ,
2506+ "Given transport module #{ inspect ( transport_mod ) } does not " <>
2507+ "implement the BACnet transport behaviour"
2508+ end
24462509 end
24472510 end
24482511
0 commit comments