Skip to content

Commit 07a5bbf

Browse files
committed
rpc_client: internal timeouts
Add internal timeouts when waiting for `RPC_RSP` and `RPC_DATA_ACK` packets. Signed-off-by: Jordan Yates <jordan@embeint.com>
1 parent 6d8c1da commit 07a5bbf

5 files changed

Lines changed: 41 additions & 13 deletions

File tree

scripts/apn_set.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ def announce_observed(self, live: Live, infuse_id: int, pkt: readings.announce |
7878
hdr, rsp = rpc_client.run_standard_cmd(
7979
rpc.kv_write.COMMAND_ID, Auth.DEVICE, params, self.response.vla_from_buffer_copy
8080
)
81+
if hdr is None:
82+
return
8183
if hdr.return_code == 0:
8284
assert rsp is not None and hasattr(rsp, "rc")
8385
if rsp.rc[0] == 0:

scripts/reboot_count_reset.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ def announce_observed(self, live: Live, infuse_id: int, pkt: readings.announce |
6767
hdr, _ = rpc_client.run_standard_cmd(
6868
rpc.kv_write.COMMAND_ID, Auth.DEVICE, params, rpc.kv_write.response.from_buffer_copy
6969
)
70+
if hdr is None:
71+
return
7072
if hdr.return_code == 0:
7173
self.updated.append(infuse_id)
7274

src/infuse_iot/rpc_client.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import ctypes
44
import random
5+
import time
56
from collections.abc import Callable
67

78
from infuse_iot import rpc
@@ -25,11 +26,15 @@ def __init__(
2526
rx_cb: Callable[[ClientNotification], None] | None = None,
2627
):
2728
self._request_id = random.randint(0, 2**31 - 1)
29+
self._timeout = 10.0
2830
self._client = client
2931
self._id = infuse_id
3032
self._max_payload = max_payload
3133
self._rx_cb = rx_cb
3234

35+
def set_timeout(self, timeout: float):
36+
self._timeout = timeout
37+
3338
def _finalise_command(
3439
self, rpc_rsp: PacketReceived, rsp_decoder: Callable[[bytes], ctypes.LittleEndianStructure]
3540
) -> tuple[rpc.ResponseHeader, ctypes.LittleEndianStructure | None]:
@@ -48,8 +53,9 @@ def _client_recv(self) -> ClientNotification | None:
4853
self._rx_cb(rsp)
4954
return rsp
5055

51-
def _wait_data_ack(self) -> PacketReceived:
52-
while True:
56+
def _wait_data_ack(self) -> PacketReceived | None:
57+
timeout = time.time() + self._timeout
58+
while time.time() < timeout:
5359
rsp = self._client_recv()
5460
if rsp is None:
5561
continue
@@ -66,10 +72,12 @@ def _wait_data_ack(self) -> PacketReceived:
6672
if data_ack.request_id != self._request_id:
6773
continue
6874
return rsp.epacket
75+
return None
6976

70-
def _wait_rpc_rsp(self) -> PacketReceived:
77+
def _wait_rpc_rsp(self) -> PacketReceived | None:
78+
timeout = time.time() + self._timeout
7179
# Wait for responses
72-
while True:
80+
while time.time() < timeout:
7381
rsp = self._client_recv()
7482
if rsp is None:
7583
continue
@@ -83,6 +91,7 @@ def _wait_rpc_rsp(self) -> PacketReceived:
8391
if rsp_header.request_id != self._request_id:
8492
continue
8593
return rsp.epacket
94+
return None
8695

8796
def _run_data_send_core(
8897
self,
@@ -94,7 +103,7 @@ def _run_data_send_core(
94103
packet_idx: bool,
95104
progress_cb: Callable[[int], None] | None,
96105
rsp_decoder: Callable[[bytes], ctypes.LittleEndianStructure],
97-
) -> tuple[rpc.ResponseHeader, ctypes.LittleEndianStructure | None]:
106+
) -> tuple[rpc.ResponseHeader | None, ctypes.LittleEndianStructure | None]:
98107
self._request_id += 1
99108
ack_period = 2
100109
header = rpc.RequestHeader(self._request_id, cmd_id) # type: ignore
@@ -112,6 +121,8 @@ def _run_data_send_core(
112121

113122
# Wait for initial ACK
114123
recv = self._wait_data_ack()
124+
if recv is None:
125+
return None, None
115126
if recv.ptype == InfuseType.RPC_RSP:
116127
return self._finalise_command(recv, rsp_decoder)
117128

@@ -133,6 +144,8 @@ def _run_data_send_core(
133144
# Wait for ACKs at the period
134145
if ack_cnt == ack_period:
135146
recv = self._wait_data_ack()
147+
if recv is None:
148+
return None, None
136149
if recv.ptype == InfuseType.RPC_RSP:
137150
return self._finalise_command(recv, rsp_decoder)
138151
ack_cnt = 0
@@ -142,6 +155,9 @@ def _run_data_send_core(
142155
progress_cb(chunk_id + 1 if packet_idx else offset)
143156

144157
recv = self._wait_rpc_rsp()
158+
if recv is None:
159+
return None, None
160+
145161
return self._finalise_command(recv, rsp_decoder)
146162

147163
def run_data_send_cmd(
@@ -152,7 +168,7 @@ def run_data_send_cmd(
152168
data: bytes,
153169
progress_cb: Callable[[int], None] | None,
154170
rsp_decoder: Callable[[bytes], ctypes.LittleEndianStructure],
155-
) -> tuple[rpc.ResponseHeader, ctypes.LittleEndianStructure | None]:
171+
) -> tuple[rpc.ResponseHeader | None, ctypes.LittleEndianStructure | None]:
156172
# Maxmimum payload size of interface
157173
size = self._max_payload - ctypes.sizeof(rpc.DataHeader)
158174
# Round payload down to multiple of 4 bytes
@@ -170,7 +186,7 @@ def run_data_send_cmd_chunked(
170186
data: list[bytes],
171187
progress_cb: Callable[[int], None] | None,
172188
rsp_decoder: Callable[[bytes], ctypes.LittleEndianStructure],
173-
) -> tuple[rpc.ResponseHeader, ctypes.LittleEndianStructure | None]:
189+
) -> tuple[rpc.ResponseHeader | None, ctypes.LittleEndianStructure | None]:
174190
return self._run_data_send_core(cmd_id, auth, params, data, len(data), True, progress_cb, rsp_decoder)
175191

176192
def run_data_recv_cmd(
@@ -225,7 +241,7 @@ def run_data_recv_cmd(
225241

226242
def run_standard_cmd(
227243
self, cmd_id: int, auth: Auth, params: bytes, rsp_decoder: Callable[[bytes], ctypes.LittleEndianStructure]
228-
) -> tuple[rpc.ResponseHeader, ctypes.LittleEndianStructure | None]:
244+
) -> tuple[rpc.ResponseHeader | None, ctypes.LittleEndianStructure | None]:
229245
self._request_id += 1
230246
header = rpc.RequestHeader(self._request_id, cmd_id) # type: ignore
231247

@@ -239,4 +255,6 @@ def run_standard_cmd(
239255
req = GatewayRequestEpacketSend(pkt)
240256
self._client.send(req)
241257
recv = self._wait_rpc_rsp()
258+
if recv is None:
259+
return None, None
242260
return self._finalise_command(recv, rsp_decoder)

src/infuse_iot/tools/ota_upgrade.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,9 @@ def gateway_diff_load(self):
153153
None,
154154
file_write_basic.response.from_buffer_copy,
155155
)
156-
if hdr.return_code != 0:
157-
sys.exit(f"Failed to save diff file to gateway (({errno.strerror(-hdr.return_code)}))")
156+
return_code = hdr.return_code if hdr else -1
157+
if return_code != 0:
158+
sys.exit(f"Failed to save diff file to gateway (({errno.strerror(-return_code)}))")
158159
print(f"'{self._single_diff}' written to gateway")
159160

160161
def run_file_upload(self, live: Live, mtu: int, source: HopReceived):
@@ -172,7 +173,9 @@ def run_file_upload(self, live: Live, mtu: int, source: HopReceived):
172173
file_write_basic.response.from_buffer_copy,
173174
)
174175

175-
if hdr.return_code == 0:
176+
if hdr is None:
177+
self._failed += 1
178+
elif hdr.return_code == 0:
176179
self._pending[source.infuse_id] = time.time() + 60
177180

178181
def run_file_copy(self, live: Live, mtu: int, source: HopReceived):
@@ -195,7 +198,9 @@ def run_file_copy(self, live: Live, mtu: int, source: HopReceived):
195198
bytes(params),
196199
bt_file_copy_basic.response.from_buffer_copy,
197200
)
198-
if hdr.return_code == 0:
201+
if hdr is None:
202+
self._failed += 1
203+
elif hdr.return_code == 0:
199204
self._pending[source.infuse_id] = time.time() + 60
200205

201206
def run(self):

src/infuse_iot/tools/rpc.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,9 @@ def run(self):
126126
params,
127127
decode_fn,
128128
)
129+
return_code = hdr.return_code if hdr else -1
129130
# Handle response
130-
self._command.handle_response(hdr.return_code, rsp)
131+
self._command.handle_response(return_code, rsp)
131132

132133
if self._args.conn_log:
133134
while True:

0 commit comments

Comments
 (0)