Skip to content

Commit feac369

Browse files
committed
added retries; increased heap -> 128K (to support redundant interfaces)
1 parent eb20155 commit feac369

File tree

4 files changed

+83
-60
lines changed

4 files changed

+83
-60
lines changed

libcyphal_demo/src/application.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
namespace
2424
{
2525

26-
constexpr std::size_t HeapSize = 32ULL * 1024ULL;
26+
constexpr std::size_t HeapSize = 128ULL * 1024ULL;
2727
alignas(O1HEAP_ALIGNMENT) std::array<cetl::byte, HeapSize> s_heap_arena{}; // NOLINT
2828

2929
constexpr std::size_t BlockHeapSize = 128ULL * 1024ULL;

libcyphal_demo/src/file_downloader.hpp

Lines changed: 75 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,8 @@ class FileDownloader final
3737
return FileDownloader{presentation, time_provider};
3838
}
3939

40-
FileDownloader(FileDownloader&& other) noexcept
41-
: presentation_{other.presentation_}
42-
, time_provider_{other.time_provider_}
43-
, get_info_client_{std::move(other.get_info_client_)}
44-
, get_info_promise_{std::move(other.get_info_promise_)}
45-
, read_client_{std::move(other.read_client_)}
46-
, read_promise_{std::move(other.read_promise_)}
47-
, read_request_{std::move(other.read_request_)}
48-
, file_stats_{other.file_stats_}
49-
{
50-
}
51-
52-
~FileDownloader() = default;
40+
FileDownloader(FileDownloader&& other) noexcept = default;
41+
~FileDownloader() = default;
5342

5443
FileDownloader(const FileDownloader&) = delete;
5544
FileDownloader& operator=(const FileDownloader&) = delete;
@@ -62,33 +51,25 @@ class FileDownloader final
6251
read_promise_.reset();
6352
read_client_.reset();
6453

65-
file_stats_.file_size = 0;
66-
file_stats_.file_progress = 0;
67-
file_stats_.file_error.value = uavcan::file::Error_1_0::OK;
54+
state_.file_size = 0;
55+
state_.file_progress = 0;
56+
state_.file_path = file_path;
57+
state_.start_time = time_provider_.now();
58+
state_.file_error.value = uavcan::file::Error_1_0::OK;
6859

6960
get_info_client_ = makeClient<Svc::GetInfo>("GetInfo", remote_node_id);
7061
read_client_ = makeClient<Svc::Read>("Read", remote_node_id);
7162
if (!get_info_client_ || !read_client_)
7263
{
73-
file_stats_.file_error.value = uavcan::file::Error_1_0::UNKNOWN_ERROR;
64+
state_.file_error.value = uavcan::file::Error_1_0::UNKNOWN_ERROR;
7465
return false;
7566
}
7667

7768
read_request_.offset = 0;
78-
file_stats_.start_time = time_provider_.now();
7969
read_request_.path.path = {file_path.begin(), file_path.end(), &presentation_.memory()};
8070

8171
std::cout << "Getting file info (path='" << file_path << "')...\n";
82-
Svc::GetInfo::Request gi_request{&presentation_.memory()};
83-
gi_request.path.path = {file_path.begin(), file_path.end(), &presentation_.memory()};
84-
return makeRequest<Svc::GetInfo>("GetInfo",
85-
get_info_client_,
86-
get_info_promise_,
87-
gi_request,
88-
[this](const auto& arg) {
89-
//
90-
handleGetInfoPromiseResult(arg.result);
91-
});
72+
return initiateGetInfoRequest();
9273
}
9374

9475
private:
@@ -111,14 +92,16 @@ class FileDownloader final
11192

11293
}; // Svc
11394

114-
struct FileStats
95+
struct State
11596
{
97+
std::string file_path;
11698
uavcan::file::Error_1_0 file_error;
11799
libcyphal::TimePoint start_time;
118100
std::size_t file_size{0};
119101
std::size_t file_progress{0};
102+
int failed_requests{0};
120103

121-
}; // FileStats
104+
}; // State
122105

123106
FileDownloader(Presentation& presentation, libcyphal::ITimeProvider& time_provider)
124107
: presentation_{presentation}
@@ -155,7 +138,7 @@ class FileDownloader final
155138
if (const auto* const failure = cetl::get_if<typename Service::Failure>(&maybe_promise))
156139
{
157140
(void) failure;
158-
file_stats_.file_error.value = uavcan::file::Error_1_0::UNKNOWN_ERROR;
141+
state_.file_error.value = uavcan::file::Error_1_0::UNKNOWN_ERROR;
159142
std::cerr << "Can't make '" << role << "' request.\n";
160143
complete();
161144
return false;
@@ -166,40 +149,64 @@ class FileDownloader final
166149
return true;
167150
}
168151

152+
bool initiateGetInfoRequest()
153+
{
154+
Svc::GetInfo::Request request{&presentation_.memory()};
155+
request.path.path = {state_.file_path.begin(), state_.file_path.end(), &presentation_.memory()};
156+
return makeRequest<Svc::GetInfo>("GetInfo",
157+
get_info_client_,
158+
get_info_promise_,
159+
request,
160+
[this](const auto& arg) {
161+
//
162+
handleGetInfoPromiseResult(arg.result);
163+
});
164+
}
165+
169166
void handleGetInfoPromiseResult(const Svc::GetInfo::Promise::Result& result)
170167
{
171168
if (const auto* const failure = cetl::get_if<ResponsePromiseFailure>(&result))
172169
{
173170
(void) failure;
174-
file_stats_.file_error.value = uavcan::file::Error_1_0::UNKNOWN_ERROR;
175-
std::cerr << "GetInfo request failed.\n";
176-
complete();
171+
state_.failed_requests++;
172+
if (state_.failed_requests >= MaxRetriesOnRequestFailure)
173+
{
174+
std::cerr << "'GetInfo' request failed (times=" << state_.failed_requests << ").\n";
175+
state_.file_error.value = uavcan::file::Error_1_0::UNKNOWN_ERROR;
176+
complete();
177+
}
178+
else
179+
{
180+
std::cerr << "'GetInfo' request failed (times=" << state_.failed_requests << "). Retrying…\n";
181+
initiateGetInfoRequest();
182+
}
177183
return;
178184
}
179-
const auto success = cetl::get<Svc::GetInfo::Promise::Success>(result);
185+
state_.failed_requests = 0;
186+
const auto success = cetl::get<Svc::GetInfo::Promise::Success>(result);
180187

181188
get_info_promise_.reset();
182189
get_info_client_.reset();
183190

184191
const auto& response = success.response;
185192
if (response._error.value == uavcan::file::Error_1_0::OK)
186193
{
187-
file_stats_.file_size = response.size;
188-
std::cout << "Downloading (size=" << file_stats_.file_size << ") ...\n";
189-
if (file_stats_.file_size > 0)
194+
state_.file_size = response.size;
195+
std::cout << "Downloading (size=" << state_.file_size << ") ...\n";
196+
if (state_.file_size > 0)
190197
{
191-
file_stats_.start_time = time_provider_.now();
198+
state_.start_time = time_provider_.now();
192199

193200
printProgress();
194201
initiateNextReadRequest();
195202
return;
196203
}
197204

198-
file_stats_.file_error.value = uavcan::file::Error_1_0::OK;
205+
state_.file_error.value = uavcan::file::Error_1_0::OK;
199206
}
200207
else
201208
{
202-
file_stats_.file_error = response._error;
209+
state_.file_error = response._error;
203210
std::cerr << "Can't get file info (err=" << response._error.value << ").\n";
204211
}
205212

@@ -219,11 +226,22 @@ class FileDownloader final
219226
if (const auto* const failure = cetl::get_if<ResponsePromiseFailure>(&result))
220227
{
221228
(void) failure;
222-
file_stats_.file_error.value = uavcan::file::Error_1_0::UNKNOWN_ERROR;
223-
std::cerr << "Read request failed.\n";
224-
complete();
229+
state_.failed_requests++;
230+
if (state_.failed_requests >= MaxRetriesOnRequestFailure)
231+
{
232+
std::cerr << "'Read' request failed (times=" << state_.failed_requests << ").\n";
233+
state_.file_error.value = uavcan::file::Error_1_0::UNKNOWN_ERROR;
234+
complete();
235+
}
236+
else
237+
{
238+
std::cerr << "'Read' request failed (times=" << state_.failed_requests << "). Retrying…\n";
239+
initiateNextReadRequest();
240+
}
225241
return;
226242
}
243+
state_.failed_requests = 0;
244+
227245
const auto success = cetl::get<Svc::Read::Promise::Success>(std::move(result));
228246

229247
const auto& response = success.response;
@@ -243,25 +261,25 @@ class FileDownloader final
243261
}
244262
else
245263
{
246-
file_stats_.file_error = response._error;
264+
state_.file_error = response._error;
247265
std::cerr << "Can't read file (err=" << response._error.value << ").\n";
248266
}
249267
complete();
250268
}
251269

252270
void printProgress()
253271
{
254-
CETL_DEBUG_ASSERT(file_stats_.file_size > 0, "");
255-
CETL_DEBUG_ASSERT(read_request_.offset <= file_stats_.file_size, "");
272+
CETL_DEBUG_ASSERT(state_.file_size > 0, "");
273+
CETL_DEBUG_ASSERT(read_request_.offset <= state_.file_size, "");
256274

257-
const auto progress = (read_request_.offset * 100U) / file_stats_.file_size;
275+
const auto progress = (read_request_.offset * 100U) / state_.file_size;
258276
CETL_DEBUG_ASSERT(progress <= 100U, "");
259277

260278
// Print progress only if its integer % has changed (or in the beginning).
261-
if ((progress != file_stats_.file_progress) || (read_request_.offset == 0))
279+
if ((progress != state_.file_progress) || (read_request_.offset == 0))
262280
{
263-
file_stats_.file_progress = progress;
264-
const auto duration = time_provider_.now() - file_stats_.start_time;
281+
state_.file_progress = progress;
282+
const auto duration = time_provider_.now() - state_.start_time;
265283
if (const auto duration_us = std::chrono::duration_cast<std::chrono::microseconds>(duration).count())
266284
{
267285
const auto speed_kb_per_sec = (read_request_.offset * 1000000U) / (duration_us * 1024U);
@@ -277,9 +295,9 @@ class FileDownloader final
277295

278296
void complete()
279297
{
280-
const auto duration = time_provider_.now() - file_stats_.start_time;
281-
std::cout << "\nDownload completed (err=" << file_stats_.file_error.value //
282-
<< ", time=" << std::fixed << std::setprecision(6) // NOLINT
298+
const auto duration = time_provider_.now() - state_.start_time;
299+
std::cout << "\nDownload completed (err=" << state_.file_error.value //
300+
<< ", time=" << std::fixed << std::setprecision(6) // NOLINT
283301
<< std::chrono::duration_cast<std::chrono::duration<double>>(duration).count() << "s).\n"
284302
<< std::flush;
285303

@@ -291,14 +309,16 @@ class FileDownloader final
291309

292310
// MARK: Data members:
293311

312+
static constexpr int MaxRetriesOnRequestFailure = 10;
313+
294314
Presentation& presentation_;
295315
libcyphal::ITimeProvider& time_provider_;
296316
cetl::optional<Svc::GetInfo::Client> get_info_client_;
297317
cetl::optional<Svc::GetInfo::Promise> get_info_promise_;
298318
cetl::optional<Svc::Read::Client> read_client_;
299319
cetl::optional<Svc::Read::Promise> read_promise_;
300320
Svc::Read::Request read_request_{&presentation_.memory()};
301-
FileStats file_stats_;
321+
State state_;
302322

303323
}; // FileDownloader
304324

libcyphal_demo/src/transport_bag_can.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,17 @@ struct TransportBagCan final
6565
const std::size_t block_size = mtu;
6666
const std::size_t pool_size = media_collection_.count() * TxQueueCapacity * block_size;
6767
media_block_mr_.setup(pool_size, block_size, block_alignment);
68-
69-
transport_->setTransientErrorHandler(platform::CommonHelpers::Can::transientErrorReporter);
68+
transport_->setTransientErrorHandler([](auto&) { return cetl::nullopt; });
69+
// transport_->setTransientErrorHandler(platform::CommonHelpers::Can::transientErrorReporter);
7070

7171
return transport_.get();
7272
}
7373

7474
private:
75-
static constexpr std::size_t TxQueueCapacity = 16;
75+
// Our current max `SerializationBufferSizeBytes` is 515 bytes (for `uavcan.register.Access.Request.1.0`)
76+
// Assuming CAN classic presentation MTU of 7 bytes (plus a bit of overhead like CRC and stuff),
77+
// let's calculate the required TX queue capacity, and make it twice to accommodate 2 such messages.
78+
static constexpr std::size_t TxQueueCapacity = 2 * (515U + 8U) / 7U;
7679

7780
cetl::pmr::memory_resource& general_mr_;
7881
libcyphal::IExecutor& executor_;

0 commit comments

Comments
 (0)