77from typing import Callable , Optional , TYPE_CHECKING
88
99from .network import CanError
10+ from .async_guard import ensure_not_async
1011
1112if TYPE_CHECKING :
1213 from .network import Network
@@ -96,15 +97,14 @@ def state(self) -> str:
9697 - 'RESET'
9798 - 'RESET COMMUNICATION'
9899 """
99- logger .warning ("Accessing NmtBase.state attribute is deprecated" )
100100 if self ._state in NMT_STATES :
101101 return NMT_STATES [self ._state ]
102102 else :
103103 return self ._state
104104
105105 @state .setter
106106 def state (self , new_state : str ):
107- logger .warning ("Accessing NmtBase.state setter is deprecated" )
107+ logger .warning ("Accessing NmtBase.state setter is deprecated, use set_state() " )
108108 self .set_state (new_state )
109109
110110 def set_state (self , new_state : str ):
@@ -129,6 +129,7 @@ def __init__(self, node_id: int):
129129 self .astate_update = asyncio .Condition ()
130130 self ._callbacks = []
131131
132+ @ensure_not_async # NOTE: Safeguard for accidental async use
132133 def on_heartbeat (self , can_id , data , timestamp ):
133134 # NOTE: Callback. Called from another thread unless async
134135 with self .state_update : # NOTE: Blocking call
@@ -177,6 +178,7 @@ def send_command(self, code: int):
177178 "Sending NMT command 0x%X to node %d" , code , self .id )
178179 self .network .send_message (0 , [code , self .id ])
179180
181+ @ensure_not_async # NOTE: Safeguard for accidental async use
180182 def wait_for_heartbeat (self , timeout : float = 10 ):
181183 """Wait until a heartbeat message is received."""
182184 with self .state_update : # NOTE: Blocking call
@@ -186,6 +188,17 @@ def wait_for_heartbeat(self, timeout: float = 10):
186188 raise NmtError ("No boot-up or heartbeat received" )
187189 return self .state
188190
191+ async def await_for_heartbeat (self , timeout : float = 10 ):
192+ """Wait until a heartbeat message is received."""
193+ async with self .astate_update :
194+ self ._state_received = None
195+ try :
196+ await asyncio .wait_for (self .astate_update .wait (), timeout = timeout )
197+ except asyncio .TimeoutError :
198+ raise NmtError ("No boot-up or heartbeat received" )
199+ return self .state
200+
201+ @ensure_not_async # NOTE: Safeguard for accidental async use
189202 def wait_for_bootup (self , timeout : float = 10 ) -> None :
190203 """Wait until a boot-up message is received."""
191204 end_time = time .time () + timeout
@@ -199,6 +212,20 @@ def wait_for_bootup(self, timeout: float = 10) -> None:
199212 if self ._state_received == 0 :
200213 break
201214
215+ async def await_for_bootup (self , timeout : float = 10 ) -> None :
216+ """Wait until a boot-up message is received."""
217+ async def wait_for_bootup ():
218+ while True :
219+ async with self .astate_update :
220+ self ._state_received = None
221+ await self .astate_update .wait ()
222+ if self ._state_received == 0 :
223+ return
224+ try :
225+ await asyncio .wait_for (wait_for_bootup (), timeout = timeout )
226+ except asyncio .TimeoutError :
227+ raise NmtError ("Timeout waiting for boot-up message" )
228+
202229 def add_hearbeat_callback (self , callback : Callable [[int ], None ]):
203230 """Add function to be called on heartbeat reception.
204231
@@ -255,7 +282,7 @@ def send_command(self, code: int) -> None:
255282 # The heartbeat service should start on the transition
256283 # between INITIALIZING and PRE-OPERATIONAL state
257284 if old_state == 0 and self ._state == 127 :
258- heartbeat_time_ms = self ._local_node .sdo [0x1017 ].get_raw ()
285+ heartbeat_time_ms = self ._local_node .sdo [0x1017 ].get_raw () # FIXME: Blocking?
259286 self .start_heartbeat (heartbeat_time_ms )
260287 else :
261288 self .update_heartbeat ()
0 commit comments