@@ -620,6 +620,14 @@ if Code.ensure_loaded?(Circuits.UART) do
620620 GenServer . call ( transport , { :is_destination_routed , destination } )
621621 end
622622
623+ @ doc """
624+ Verifies whether the given destination is valid for the transport module.
625+ """
626+ @ spec is_valid_destination ( destination_address ( ) ) :: boolean ( )
627+ def is_valid_destination ( destination ) do
628+ is_integer ( destination ) and destination >= 0 and destination <= 255
629+ end
630+
623631 @ doc """
624632 Sends data to the BACnet network.
625633
@@ -792,11 +800,29 @@ if Code.ensure_loaded?(Circuits.UART) do
792800 end
793801
794802 @ doc """
795- Verifies whether the given destination is valid for the transport module.
803+ Sends a Reply-Postponed Frame to the destination.
804+
805+ Sending an explicit Reply-Postponed Frame is necessary,
806+ when the reply is to be segmented.
807+ A segmented Complex-ACK APDU can only be transmitted
808+ when we hold the token (ASHRAE 135 Clause 9.8).
809+
810+ There are no options at this time.
796811 """
797- @ spec is_valid_destination ( destination_address ( ) ) :: boolean ( )
798- def is_valid_destination ( destination ) do
799- is_integer ( destination ) and destination >= 0 and destination <= 255
812+ @ spec reply_postponed (
813+ portal :: TransportBehaviour . portal ( ) ,
814+ destination :: source_address ( ) ,
815+ opts :: Keyword . t ( )
816+ ) ::
817+ :ok
818+ | { :error , term ( ) }
819+ | { :error , :slave_mode }
820+ | { :error , :no_reply_pending }
821+ | { :error , :destination_is_not_expecting_reply }
822+ def reply_postponed ( portal , destination , opts \\ [ ] )
823+ when is_server ( portal ) and is_integer ( destination ) and destination >= 0 and
824+ destination <= 254 and is_list ( opts ) do
825+ GenServer . call ( portal , { :reply_postponed , destination , opts } , @ call_timeout )
800826 end
801827
802828 @ doc false
@@ -1311,6 +1337,63 @@ if Code.ensure_loaded?(Circuits.UART) do
13111337 { :stop , :normal , :ok , state }
13121338 end
13131339
1340+ def handle_call ( :get_state , _from , % State { } = state ) do
1341+ log_debug ( fn ->
1342+ "BacMstpTransport: Received get_state request"
1343+ end )
1344+
1345+ { :reply , state . transport_state , state }
1346+ end
1347+
1348+ def handle_call ( :disable_token_passing , _from , % State { local_address: local_addr } = state )
1349+ when local_addr < @ min_slave_addr do
1350+ log_debug ( fn ->
1351+ "BacMstpTransport: Received disable_token_passing request during state " <>
1352+ String . upcase ( Atom . to_string ( state . transport_state ) )
1353+ end )
1354+
1355+ new_state = % { state | disable_token_passing: true }
1356+
1357+ { :reply , :ok , new_state }
1358+ end
1359+
1360+ def handle_call ( :disable_token_passing , _from , % State { } = state ) do
1361+ log_debug ( fn ->
1362+ "BacMstpTransport: Received disable_token_passing reques in slave_mode"
1363+ end )
1364+
1365+ { :reply , { :error , :slave_mode } , state }
1366+ end
1367+
1368+ def handle_call ( { :configure , % { } = opts } , _from , % State { } = state ) do
1369+ log_debug ( fn -> "BacMstpTransport: Received configure request" end )
1370+
1371+ new_opts = Map . merge ( state . opts , opts )
1372+
1373+ reply =
1374+ case Map . fetch ( opts , :baudrate ) do
1375+ { :ok , baudrate } ->
1376+ with :ok <- UART . configure ( state . uart_pid , speed: baudrate ) do
1377+ ReceiveFSM . configure ( state . receive_fsm , % {
1378+ baudrate: baudrate ,
1379+ log_communication: new_opts . log_communication_rcv
1380+ } )
1381+ end
1382+
1383+ :error ->
1384+ :ok
1385+ end
1386+
1387+ case reply do
1388+ :ok ->
1389+ new_state = % { state | opts: new_opts }
1390+ { :reply , :ok , new_state }
1391+
1392+ _other ->
1393+ { :reply , reply , state }
1394+ end
1395+ end
1396+
13141397 def handle_call ( :get_local_address , _from , % State { } = state ) do
13151398 log_debug ( "BacMstpTransport: Received get_local_address request" )
13161399
@@ -1357,7 +1440,7 @@ if Code.ensure_loaded?(Circuits.UART) do
13571440
13581441 { reply , new_state } =
13591442 send_frame_data_not_expecting_reply (
1360- % { state | transport_state: :idle } ,
1443+ % { state | transport_state: :idle , answer_invoke_id: nil } ,
13611444 destination ,
13621445 data
13631446 )
@@ -1483,63 +1566,46 @@ if Code.ensure_loaded?(Circuits.UART) do
14831566 { :reply , { :error , :slave_mode } , state }
14841567 end
14851568
1486- def handle_call ( :get_state , _from , % State { } = state ) do
1569+ def handle_call (
1570+ { :reply_postponed , destination , _opts } ,
1571+ _from ,
1572+ % State { local_address: local_addr , state_machine: % { source_address: source } } = state
1573+ )
1574+ when local_addr < @ min_slave_addr do
14871575 log_debug ( fn ->
1488- "BacMstpTransport: Received get_state request"
1576+ "BacMstpTransport: Received reply_postponed request"
14891577 end )
14901578
1491- { :reply , state . transport_state , state }
1492- end
1579+ { reply , new_state } =
1580+ cond do
1581+ source != destination ->
1582+ { { :error , :destination_is_not_expecting_reply } , state }
14931583
1494- def handle_call ( :disable_token_passing , _from , % State { local_address: local_addr } = state )
1495- when local_addr < @ min_slave_addr do
1496- log_debug ( fn ->
1497- "BacMstpTransport: Received disable_token_passing request during state " <>
1498- String . upcase ( Atom . to_string ( state . transport_state ) )
1499- end )
1584+ state . transport_state == :answer_data_request ->
1585+ # Remove the reply timer
1586+ state = state_cancel_silence_timer ( state )
1587+ state = state_set_silence_timer ( state , :timer_lost_token , @ param_t_no_token )
15001588
1501- new_state = % { state | disable_token_passing: true }
1589+ case send_frame_reply_postponed ( state , destination ) do
1590+ { :ok , state } -> { :ok , % { state | transport_state: :idle , answer_invoke_id: nil } }
1591+ { :error , state } -> { { :error , :sending_failed } , state }
1592+ end
15021593
1503- { :reply , :ok , new_state }
1594+ true ->
1595+ { { :error , :no_reply_pending } , state }
1596+ end
1597+
1598+ { :reply , reply , new_state }
15041599 end
15051600
1506- def handle_call ( :disable_token_passing , _from , % State { } = state ) do
1601+ def handle_call ( { :reply_postponed , _destination , _opts } , _from , % State { } = state ) do
15071602 log_debug ( fn ->
1508- "BacMstpTransport: Received disable_token_passing reques in slave_mode "
1603+ "BacMstpTransport: Received reply_postponed request in slave mode "
15091604 end )
15101605
15111606 { :reply , { :error , :slave_mode } , state }
15121607 end
15131608
1514- def handle_call ( { :configure , % { } = opts } , _from , % State { } = state ) do
1515- log_debug ( fn -> "BacMstpTransport: Received configure request" end )
1516-
1517- new_opts = Map . merge ( state . opts , opts )
1518-
1519- reply =
1520- case Map . fetch ( opts , :baudrate ) do
1521- { :ok , baudrate } ->
1522- with :ok <- UART . configure ( state . uart_pid , speed: baudrate ) do
1523- ReceiveFSM . configure ( state . receive_fsm , % {
1524- baudrate: baudrate ,
1525- log_communication: new_opts . log_communication_rcv
1526- } )
1527- end
1528-
1529- :error ->
1530- :ok
1531- end
1532-
1533- case reply do
1534- :ok ->
1535- new_state = % { state | opts: new_opts }
1536- { :reply , :ok , new_state }
1537-
1538- _other ->
1539- { :reply , reply , state }
1540- end
1541- end
1542-
15431609 def handle_call ( _call , _from , state ) do
15441610 { :noreply , state }
15451611 end
0 commit comments