Skip to content

Commit 947fcd3

Browse files
fix: address PR review findings across atracsys pipeline
- Move parse_arguments inside try/catch in main to prevent uncaught exceptions from std::terminate on bad CLI input - Use size-tracked std::string construction for ftkBuffer error messages in atracsys_device.hpp to avoid reading past buffer length - Guard static cache initialization in geometry_helper.cpp with std::once_flag/std::call_once for thread safety - Fix ftkEnumerateDevices error check from '> FTK_OK' to '!= FTK_OK' in helpers.cpp to correctly catch all non-OK returns - Qualify optionEnumerator as atracsys::sdk::optionEnumerator and move anonymous namespace helpers to atracsys::sdk::detail in s3dk_wrapper.hpp - Always throw on ftkSetInt32 failure in set_device_option regardless of required flag, include status code in error message - Add explicit #include <stdexcept> and <string> to sdk_wrapper.hpp - Add defensive HOLOHUB_DATA_DIR check in CMakeLists.txt - Move AsynchronousCondition discovery to start of start() in master_source_op.cpp to avoid resource leaks on missing condition - Expose min_z/max_z/max_x/max_y as operator parameters in PointCloudFilterOp instead of hardcoded literals - Add proper Expected<T> validation before .value() calls in point_cloud_filter_op.cpp for clearer error diagnostics - Qualify std::ios, std::streamsize, std::cerr in geometry_helper.cpp Signed-off-by: Artrit Telaku <[email protected]> Signed-off-by: artrittelaku-wayland <[email protected]>
1 parent a874bf4 commit 947fcd3

10 files changed

Lines changed: 124 additions & 80 deletions

File tree

applications/atracsys_visualizer/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ else()
4444
endif()
4545
endif()
4646

47+
if(NOT DEFINED HOLOHUB_DATA_DIR OR HOLOHUB_DATA_DIR STREQUAL "")
48+
message(FATAL_ERROR "HOLOHUB_DATA_DIR must be set when building with datasets")
49+
endif()
50+
4751
if(HOLOHUB_DOWNLOAD_DATASETS AND NOT EXISTS "${HOLOHUB_DATA_DIR}/atracsys_visualizer/ir_base.gxf_entities")
4852
set(ATRACSYS_VISUALIZER_DATASET_URL
4953
"https://github.com/waylandio/holohub/releases/download/dataset-v1.0/atracsys_visualizer.zip")

applications/atracsys_visualizer/cpp/atracsys_visualizer.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -246,24 +246,24 @@ class AtracsysVisualizerApp : public holoscan::Application {
246246
};
247247

248248
int main(int argc, char** argv) {
249-
CommandLineOptions options;
250-
if (!parse_arguments(argc, argv, options)) {
251-
return 0;
252-
}
249+
try {
250+
CommandLineOptions options;
251+
if (!parse_arguments(argc, argv, options)) {
252+
return 0;
253+
}
253254

254-
if (options.config_path.empty()) {
255-
options.config_path = "atracsys_visualizer.yaml";
256-
}
255+
if (options.config_path.empty()) {
256+
options.config_path = "atracsys_visualizer.yaml";
257+
}
257258

258-
if (options.data_path.empty()) {
259-
if (const char* env_path = std::getenv("HOLOSCAN_INPUT_PATH")) {
260-
options.data_path = env_path;
261-
} else {
262-
options.data_path = "data/atracsys_visualizer";
259+
if (options.data_path.empty()) {
260+
if (const char* env_path = std::getenv("HOLOSCAN_INPUT_PATH")) {
261+
options.data_path = env_path;
262+
} else {
263+
options.data_path = "data/atracsys_visualizer";
264+
}
263265
}
264-
}
265266

266-
try {
267267
auto app = holoscan::make_application<AtracsysVisualizerApp>();
268268
app->set_source(options.source);
269269
app->set_data_path(options.data_path);

operators/atracsys_camera/master_source_op.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,19 @@ void AtracsysMasterSourceOp::setup(holoscan::OperatorSpec& spec) {
183183

184184
void AtracsysMasterSourceOp::start() {
185185
reset_state();
186+
187+
for (auto& [name, cond] : conditions()) {
188+
if (auto async_cond = std::dynamic_pointer_cast<holoscan::AsynchronousCondition>(cond)) {
189+
async_cond_ = async_cond;
190+
break;
191+
}
192+
}
193+
if (!async_cond_) {
194+
throw std::runtime_error(
195+
"AtracsysMasterSourceOp: AsyncCondition not found. The app must provide an "
196+
"AsynchronousCondition.");
197+
}
198+
186199
frame_timeout_count_ = 0;
187200
first_frame_logged_ = false;
188201
first_structured_cloud_logged_ = false;
@@ -222,18 +235,6 @@ void AtracsysMasterSourceOp::start() {
222235
stereo_params_->scale = validated_scale_factor(scale_factor_.get());
223236
}
224237

225-
for (auto& [name, cond] : conditions()) {
226-
if (auto async_cond = std::dynamic_pointer_cast<holoscan::AsynchronousCondition>(cond)) {
227-
async_cond_ = async_cond;
228-
break;
229-
}
230-
}
231-
if (!async_cond_) {
232-
throw std::runtime_error(
233-
"AtracsysMasterSourceOp: AsyncCondition not found. The app must provide an "
234-
"AsynchronousCondition.");
235-
}
236-
237238
is_running_ = true;
238239
async_cond_->event_state(holoscan::AsynchronousEventState::EVENT_WAITING);
239240
capture_thread_ = std::thread(&AtracsysMasterSourceOp::capture_loop, this);

operators/atracsys_camera/point_cloud_filter_op.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ void PointCloudFilterOp::setup(holoscan::OperatorSpec& spec) {
5353
"cuda_stream_pool",
5454
"CudaStreamPool",
5555
"CUDA stream pool used for async GPU operations");
56+
57+
spec.param(min_z_, "min_z", "Min Z", "Minimum Z coordinate for points", 0.0f);
58+
spec.param(max_z_, "max_z", "Max Z", "Maximum Z coordinate for points", 5000.0f);
59+
spec.param(max_x_, "max_x", "Max X", "Maximum absolute X coordinate for points", 5000.0f);
60+
spec.param(max_y_, "max_y", "Max Y", "Maximum absolute Y coordinate for points", 5000.0f);
5661
}
5762

5863
void PointCloudFilterOp::start() {
@@ -81,9 +86,26 @@ void PointCloudFilterOp::ensure_structured_output_entities(
8186
const nvidia::gxf::Shape shape{static_cast<int32_t>(point_count), 3};
8287
auto alloc = nvidia::gxf::Handle<nvidia::gxf::Allocator>::Create(
8388
context.context(), structured_allocator_.get()->gxf_cid());
89+
if (!alloc) {
90+
throw std::runtime_error("PointCloudFilterOp: failed to create allocator handle");
91+
}
92+
8493
auto msg = nvidia::gxf::Entity::New(context.context());
94+
if (!msg) {
95+
throw std::runtime_error("PointCloudFilterOp: failed to create new entity");
96+
}
97+
8598
auto tensor = msg.value().add<nvidia::gxf::Tensor>(kStructuredTensorName);
86-
tensor.value()->reshape<float>(shape, nvidia::gxf::MemoryStorageType::kDevice, alloc.value());
99+
if (!tensor) {
100+
throw std::runtime_error("PointCloudFilterOp: failed to add tensor to entity");
101+
}
102+
103+
auto reshape_result = tensor.value()->reshape<float>(
104+
shape, nvidia::gxf::MemoryStorageType::kDevice, alloc.value());
105+
if (!reshape_result) {
106+
throw std::runtime_error("PointCloudFilterOp: failed to reshape tensor");
107+
}
108+
87109
structured_output_entities_[structured_output_entity_index_].emplace(std::move(msg.value()));
88110
}
89111

@@ -140,10 +162,10 @@ void PointCloudFilterOp::compute(holoscan::InputContext& op_input,
140162
height,
141163
step,
142164
h_Q,
143-
0.0f,
144-
5000.0f,
145-
5000.0f,
146-
5000.0f,
165+
min_z_.get(),
166+
max_z_.get(),
167+
max_x_.get(),
168+
max_y_.get(),
147169
d_out_points,
148170
cuda_stream);
149171
check_cuda(cudaGetLastError(), "Failed to launch point cloud filter kernel");

operators/atracsys_camera/point_cloud_filter_op.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ class __attribute__((visibility("default"))) PointCloudFilterOp : public holosca
4747

4848
holoscan::Parameter<std::shared_ptr<holoscan::Allocator>> structured_allocator_;
4949
holoscan::Parameter<std::shared_ptr<holoscan::CudaStreamPool>> cuda_stream_pool_;
50+
holoscan::Parameter<float> min_z_;
51+
holoscan::Parameter<float> max_z_;
52+
holoscan::Parameter<float> max_x_;
53+
holoscan::Parameter<float> max_y_;
5054

5155
static constexpr size_t kEntityRingSize = 4;
5256
std::array<std::optional<holoscan::gxf::Entity>, kEntityRingSize> structured_output_entities_;

operators/atracsys_camera/sdk/atracsys_device.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ class AtracsysDevice {
4040

4141
ftkLibrary new_lib = ftkInitExt(nullptr, &buffer_);
4242
if (!new_lib) {
43-
throw std::runtime_error(buffer_.data ? buffer_.data : "ftkInitExt failed");
43+
if (buffer_.data && buffer_.size > 0) {
44+
throw std::runtime_error(
45+
std::string(reinterpret_cast<const char*>(buffer_.data), buffer_.size));
46+
}
47+
throw std::runtime_error("ftkInitExt failed");
4448
}
4549

4650
try {

operators/atracsys_camera/sdk/geometry_helper.cpp

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@
2323
#include <fstream>
2424
#include <iostream>
2525
#include <limits>
26+
#include <mutex>
2627
#include <string>
2728

28-
using namespace std;
29-
3029
static void getDataDirOptionId(uint64_t sn, void* user, ftkOptionsInfo* oi);
3130

32-
int loadRigidBody(ftkLibrary lib, const string& fileName, ftkRigidBody& geometry) {
33-
string fullFileName;
31+
int loadRigidBody(ftkLibrary lib, const std::string& fileName, ftkRigidBody& geometry) {
32+
std::string fullFileName;
3433
bool fromDataDir = false;
3534
if (!getFullFilePath(lib, fileName, fullFileName, &fromDataDir)) {
3635
return 2;
@@ -48,37 +47,41 @@ int loadRigidBody(ftkLibrary lib, const string& fileName, ftkRigidBody& geometry
4847
return fromDataDir ? 1 : 0;
4948
}
5049

51-
bool getFullFilePath(ftkLibrary lib, const string& fileName, string& fullFilePath,
50+
bool getFullFilePath(ftkLibrary lib, const std::string& fileName, std::string& fullFilePath,
5251
bool* fromSystem) {
5352
static uint32_t FTK_OPT_DATA_DIR = 0u;
54-
static string OPT_DIR;
53+
static std::string OPT_DIR;
54+
static std::once_flag flag;
5555

56-
if (FTK_OPT_DATA_DIR == 0u) {
56+
std::call_once(flag, [&]() {
5757
if (ftkEnumerateOptions(lib, 0uLL, getDataDirOptionId, &FTK_OPT_DATA_DIR) !=
5858
ftkError::FTK_WAR_OPT_GLOBAL_ONLY) {
59-
cerr << "Could not get the data directory option ID\n";
60-
return false;
59+
std::cerr << "Could not get the data directory option ID\n";
60+
FTK_OPT_DATA_DIR = 0u;
61+
return;
6162
}
62-
if (FTK_OPT_DATA_DIR == 0u) {
63-
cerr << "Could not get the data directory option ID\n";
64-
return false;
63+
if (FTK_OPT_DATA_DIR != 0u) {
64+
ftkBuffer buffer{};
65+
if (ftkGetData(lib, 0uLL, FTK_OPT_DATA_DIR, &buffer) == ftkError::FTK_OK &&
66+
buffer.size >= 1u) {
67+
OPT_DIR.assign(reinterpret_cast<const char*>(buffer.data), buffer.size);
68+
if (!OPT_DIR.empty() && OPT_DIR.back() == '\0') {
69+
OPT_DIR.pop_back();
70+
}
71+
}
6572
}
66-
}
73+
});
6774

75+
if (FTK_OPT_DATA_DIR == 0u) {
76+
std::cerr << "Could not get the data directory option ID\n";
77+
return false;
78+
}
6879
if (OPT_DIR.empty()) {
69-
ftkBuffer buffer{};
70-
if (ftkGetData(lib, 0uLL, FTK_OPT_DATA_DIR, &buffer) != ftkError::FTK_OK ||
71-
buffer.size < 1u) {
72-
return false;
73-
}
74-
OPT_DIR.assign(reinterpret_cast<const char*>(buffer.data), buffer.size);
75-
if (!OPT_DIR.empty() && OPT_DIR.back() == '\0') {
76-
OPT_DIR.pop_back();
77-
}
80+
return false;
7881
}
7982

80-
const string candidate = OPT_DIR + "/" + fileName;
81-
ifstream system_input{candidate};
83+
const std::string candidate = OPT_DIR + "/" + fileName;
84+
std::ifstream system_input{candidate};
8285
if (system_input.is_open()) {
8386
fullFilePath = candidate;
8487
if (fromSystem != nullptr) *fromSystem = true;
@@ -88,31 +91,31 @@ bool getFullFilePath(ftkLibrary lib, const string& fileName, string& fullFilePat
8891
return false;
8992
}
9093

91-
bool loadFileInBuffer(const string& fullFilePath, ftkBuffer& buffer) {
92-
ifstream input(fullFilePath, ios::binary | ios::ate);
94+
bool loadFileInBuffer(const std::string& fullFilePath, ftkBuffer& buffer) {
95+
std::ifstream input(fullFilePath, std::ios::binary | std::ios::ate);
9396
if (!input.is_open()) {
94-
cerr << "Could not open file '" << fullFilePath << "'\n";
97+
std::cerr << "Could not open file '" << fullFilePath << "'\n";
9598
return false;
9699
}
97100

98101
buffer.reset();
99-
streampos pos = input.tellg();
102+
std::streampos pos = input.tellg();
100103
if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
101-
cerr << "File too large for buffer\n";
104+
std::cerr << "File too large for buffer\n";
102105
return false;
103106
}
104107

105108
if (static_cast<size_t>(pos) > buffer.capacity) {
106109
if (buffer.resize(static_cast<size_t>(pos)) != ftkError::FTK_OK) {
107-
cerr << "Failed to resize ftkBuffer for file\n";
110+
std::cerr << "Failed to resize ftkBuffer for file\n";
108111
return false;
109112
}
110113
}
111114

112-
input.seekg(0u, ios::beg);
113-
input.read(buffer.data, static_cast<streamsize>(pos));
115+
input.seekg(0u, std::ios::beg);
116+
input.read(buffer.data, static_cast<std::streamsize>(pos));
114117
if (input.fail()) {
115-
cerr << "Could not read file '" << fullFilePath << "'\n";
118+
std::cerr << "Could not read file '" << fullFilePath << "'\n";
116119
return false;
117120
}
118121
buffer.size = static_cast<uint32_t>(pos);

operators/atracsys_camera/sdk/helpers.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ DeviceData retrieveLastDevice(ftkLibrary lib, bool allowSimulator, bool quiet,
5656
err = ftkEnumerateDevices(lib, fusionTrackEnumerator, &device);
5757
}
5858

59-
if (err > ftkError::FTK_OK) {
59+
if (err != ftkError::FTK_OK) {
6060
throw std::runtime_error("ftkEnumerateDevices returned an error");
6161
}
6262

operators/atracsys_camera/sdk/s3dk_wrapper.hpp

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
#include "helpers.hpp"
2727
#include "s3dk_interface.hpp"
2828

29-
namespace {
29+
namespace atracsys::sdk::detail {
3030

3131
inline std::map<std::string, uint32_t> enumerate_sdk_options(ftkLibrary lib, uint64_t sn) {
3232
std::map<std::string, uint32_t> options;
33-
if (ftkEnumerateOptions(lib, sn, optionEnumerator, &options) != ftkError::FTK_OK ||
33+
if (ftkEnumerateOptions(lib, sn, atracsys::sdk::optionEnumerator, &options) != ftkError::FTK_OK ||
3434
options.empty()) {
3535
throw std::runtime_error("Cannot retrieve Atracsys SDK options.");
3636
}
@@ -53,29 +53,30 @@ inline std::string device_type_string(ftkLibrary lib, uint64_t sn,
5353

5454
inline void set_device_option(ftkLibrary lib, uint64_t sn,
5555
const std::map<std::string, uint32_t>& options, const char* name,
56-
int32_t value, bool required = true) {
56+
int32_t value) {
5757
auto it = options.find(name);
5858
if (it == options.end()) {
59-
if (required)
60-
throw std::runtime_error(std::string("Missing Atracsys option: ") + name);
6159
return;
6260
}
6361

64-
if (ftkSetInt32(lib, sn, it->second, value) != ftkError::FTK_OK && required) {
65-
throw std::runtime_error(std::string("Failed to set Atracsys option: ") + name);
62+
const ftkError status = ftkSetInt32(lib, sn, it->second, value);
63+
if (status != ftkError::FTK_OK) {
64+
throw std::runtime_error(
65+
std::string("Failed to set Atracsys option: ") + name +
66+
", status: " + std::to_string(status));
6667
}
6768
}
6869

6970
inline void configure_device_defaults(ftkLibrary lib, uint64_t sn,
7071
const std::map<std::string, uint32_t>& options) {
7172
set_device_option(lib, sn, options, "Enable embedded processing", 1);
7273
set_device_option(lib, sn, options, "Enable images sending", 1);
73-
set_device_option(lib, sn, options, "Calibration export", 1, false);
74-
set_device_option(lib, sn, options, "Embedded Symmetrise coordinates", 0, false);
75-
set_device_option(lib, sn, options, "Enable 16 bits pictures", 0, false);
74+
set_device_option(lib, sn, options, "Calibration export", 1);
75+
set_device_option(lib, sn, options, "Embedded Symmetrise coordinates", 0);
76+
set_device_option(lib, sn, options, "Enable 16 bits pictures", 0);
7677
}
7778

78-
} // namespace
79+
} // namespace atracsys::sdk::detail
7980

8081
class RealS3DKWrapper : public atracsys::IS3DKInterface {
8182
public:
@@ -86,14 +87,16 @@ class RealS3DKWrapper : public atracsys::IS3DKInterface {
8687
if (!device_sn || !lib || !image_type) {
8788
throw std::runtime_error("initializeDeviceHelper: invalid arguments");
8889
}
89-
auto options = enumerate_sdk_options(lib, *device_sn);
90-
const std::string device_type = device_type_string(lib, *device_sn, options);
90+
auto options =
91+
atracsys::sdk::detail::enumerate_sdk_options(lib, *device_sn);
92+
const std::string device_type =
93+
atracsys::sdk::detail::device_type_string(lib, *device_sn, options);
9194
bool valid = false;
9295
*image_type = convert_string_image_type(device_type, &valid);
9396
if (!valid) {
9497
throw std::runtime_error("Unsupported Atracsys device type for S3DK: " + device_type);
9598
}
96-
configure_device_defaults(lib, *device_sn, options);
99+
atracsys::sdk::detail::configure_device_defaults(lib, *device_sn, options);
97100
return true;
98101
}
99102

operators/atracsys_camera/sdk/sdk_wrapper.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
#pragma once
1919

20+
#include <stdexcept>
21+
#include <string>
22+
2023
#include "sdk_interface.hpp"
2124

2225
class RealSDKWrapper : public atracsys::ISDKInterface {

0 commit comments

Comments
 (0)