Skip to content

Commit 4ed9886

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 <artrit@waylandio.com> Signed-off-by: artrittelaku-wayland <artrit.telaku@wayland.io>
1 parent a874bf4 commit 4ed9886

11 files changed

Lines changed: 175 additions & 114 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: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -246,24 +246,25 @@ 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 =
262+
std::string(env_path) + "/atracsys_visualizer";
263+
} else {
264+
options.data_path = "data/atracsys_visualizer";
265+
}
263266
}
264-
}
265267

266-
try {
267268
auto app = holoscan::make_application<AtracsysVisualizerApp>();
268269
app->set_source(options.source);
269270
app->set_data_path(options.data_path);

operators/atracsys_camera/master_source_op.cpp

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

184184
void AtracsysMasterSourceOp::start() {
185185
reset_state();
186-
frame_timeout_count_ = 0;
187-
first_frame_logged_ = false;
188-
first_structured_cloud_logged_ = false;
189-
190-
auto& dev = AtracsysDevice::instance();
191-
dev.init();
192-
device_sn_ = dev.serial();
193-
194-
active_scheduler_mode_ = configured_scheduler_mode();
195-
active_hw_mode_ = configured_initial_hw_mode();
196-
frame_timeout_ms_ = 500;
197-
198-
if (!s3dk_) {
199-
s3dk_ = std::make_unique<RealS3DKWrapper>();
200-
}
201-
if (!s3dk_->initializeDeviceHelper(&device_sn_, dev.lib(), &image_type_)) {
202-
throw std::runtime_error("AtracsysMasterSourceOp: initializeDeviceHelper failed");
203-
}
204-
205-
load_geometries();
206-
configure_camera();
207-
208-
frame_ = sdk_.createFrame();
209-
if (!frame_) {
210-
throw std::runtime_error("AtracsysMasterSourceOp: ftkCreateFrame failed");
211-
}
212-
configure_frame();
213-
214-
stereo_params_ = s3dk_->createStereoParameters();
215-
engine_ = s3dk_->createDefaultEngine();
216-
gpu_frame_ = s3dk_->createGpu3DFrame(image_type_);
217-
if (gpu_frame_) {
218-
const int scale = validated_scale_factor(scale_factor_.get());
219-
gpu_frame_->_scale = scale;
220-
}
221-
if (stereo_params_) {
222-
stereo_params_->scale = validated_scale_factor(scale_factor_.get());
223-
}
224186

225187
for (auto& [name, cond] : conditions()) {
226188
if (auto async_cond = std::dynamic_pointer_cast<holoscan::AsynchronousCondition>(cond)) {
@@ -234,9 +196,58 @@ void AtracsysMasterSourceOp::start() {
234196
"AsynchronousCondition.");
235197
}
236198

237-
is_running_ = true;
238-
async_cond_->event_state(holoscan::AsynchronousEventState::EVENT_WAITING);
239-
capture_thread_ = std::thread(&AtracsysMasterSourceOp::capture_loop, this);
199+
frame_timeout_count_ = 0;
200+
first_frame_logged_ = false;
201+
first_structured_cloud_logged_ = false;
202+
203+
auto& dev = AtracsysDevice::instance();
204+
dev.init();
205+
206+
try {
207+
device_sn_ = dev.serial();
208+
209+
active_scheduler_mode_ = configured_scheduler_mode();
210+
active_hw_mode_ = configured_initial_hw_mode();
211+
frame_timeout_ms_ = 500;
212+
213+
if (!s3dk_) {
214+
s3dk_ = std::make_unique<RealS3DKWrapper>();
215+
}
216+
if (!s3dk_->initializeDeviceHelper(&device_sn_, dev.lib(), &image_type_)) {
217+
throw std::runtime_error(
218+
"AtracsysMasterSourceOp: initializeDeviceHelper failed");
219+
}
220+
221+
load_geometries();
222+
configure_camera();
223+
224+
frame_ = sdk_.createFrame();
225+
if (!frame_) {
226+
throw std::runtime_error(
227+
"AtracsysMasterSourceOp: ftkCreateFrame failed");
228+
}
229+
configure_frame();
230+
231+
stereo_params_ = s3dk_->createStereoParameters();
232+
engine_ = s3dk_->createDefaultEngine();
233+
gpu_frame_ = s3dk_->createGpu3DFrame(image_type_);
234+
if (gpu_frame_) {
235+
const int scale = validated_scale_factor(scale_factor_.get());
236+
gpu_frame_->_scale = scale;
237+
}
238+
if (stereo_params_) {
239+
stereo_params_->scale = validated_scale_factor(scale_factor_.get());
240+
}
241+
242+
is_running_ = true;
243+
async_cond_->event_state(
244+
holoscan::AsynchronousEventState::EVENT_WAITING);
245+
capture_thread_ =
246+
std::thread(&AtracsysMasterSourceOp::capture_loop, this);
247+
} catch (...) {
248+
AtracsysDevice::instance().shutdown();
249+
throw;
250+
}
240251
}
241252

242253
void AtracsysMasterSourceOp::stop() {
@@ -252,6 +263,8 @@ void AtracsysMasterSourceOp::stop() {
252263
stereo_params_ = nullptr;
253264
s3dk_.reset();
254265

266+
AtracsysDevice::instance().shutdown();
267+
255268
holoscan::Operator::stop();
256269
}
257270

operators/atracsys_camera/master_source_op.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ typedef struct CUstream_st* cudaStream_t;
3636
#include "hardware_mode_command.hpp"
3737
#include "sdk/atracsys_device.hpp"
3838
#include "sdk/s3dk_interface.hpp"
39+
#include "sdk/s3dk_wrapper.hpp"
3940
#include "sdk/sdk_wrapper.hpp"
4041

4142
namespace holoscan::ops {

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: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@
1919

2020
#include <ftkInterface.h>
2121

22+
#include <cstdlib>
2223
#include <cstring>
2324
#include <fstream>
2425
#include <iostream>
2526
#include <limits>
27+
#include <mutex>
2628
#include <string>
2729

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

32-
int loadRigidBody(ftkLibrary lib, const string& fileName, ftkRigidBody& geometry) {
33-
string fullFileName;
32+
int loadRigidBody(ftkLibrary lib, const std::string& fileName, ftkRigidBody& geometry) {
33+
std::string fullFileName;
3434
bool fromDataDir = false;
3535
if (!getFullFilePath(lib, fileName, fullFileName, &fromDataDir)) {
3636
return 2;
@@ -48,37 +48,41 @@ int loadRigidBody(ftkLibrary lib, const string& fileName, ftkRigidBody& geometry
4848
return fromDataDir ? 1 : 0;
4949
}
5050

51-
bool getFullFilePath(ftkLibrary lib, const string& fileName, string& fullFilePath,
51+
bool getFullFilePath(ftkLibrary lib, const std::string& fileName, std::string& fullFilePath,
5252
bool* fromSystem) {
5353
static uint32_t FTK_OPT_DATA_DIR = 0u;
54-
static string OPT_DIR;
54+
static std::string OPT_DIR;
55+
static std::once_flag flag;
5556

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

76+
if (FTK_OPT_DATA_DIR == 0u) {
77+
std::cerr << "Could not get the data directory option ID\n";
78+
return false;
79+
}
6880
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-
}
81+
return false;
7882
}
7983

80-
const string candidate = OPT_DIR + "/" + fileName;
81-
ifstream system_input{candidate};
84+
const std::string candidate = OPT_DIR + "/" + fileName;
85+
std::ifstream system_input{candidate};
8286
if (system_input.is_open()) {
8387
fullFilePath = candidate;
8488
if (fromSystem != nullptr) *fromSystem = true;
@@ -88,31 +92,33 @@ bool getFullFilePath(ftkLibrary lib, const string& fileName, string& fullFilePat
8892
return false;
8993
}
9094

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

98102
buffer.reset();
99-
streampos pos = input.tellg();
103+
std::streampos pos = input.tellg();
100104
if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
101-
cerr << "File too large for buffer\n";
105+
std::cerr << "File too large for buffer\n";
102106
return false;
103107
}
104108

105-
if (static_cast<size_t>(pos) > buffer.capacity) {
106-
if (buffer.resize(static_cast<size_t>(pos)) != ftkError::FTK_OK) {
107-
cerr << "Failed to resize ftkBuffer for file\n";
108-
return false;
109-
}
109+
const auto file_size = static_cast<size_t>(pos);
110+
auto* raw = reinterpret_cast<char*>(std::malloc(file_size));
111+
if (!raw) {
112+
std::cerr << "Failed to allocate buffer for file\n";
113+
return false;
110114
}
115+
buffer.data = raw;
116+
buffer.size = 0u;
111117

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

0 commit comments

Comments
 (0)