Skip to content

Conversation

@hawkeyeking
Copy link

@hawkeyeking hawkeyeking commented Dec 9, 2025

Add HoloCat application that integrates EtherCAT real-time communication with NVIDIA's Holoscan streaming framework.

Key Features:

  • Real-time EtherCAT master implementation using EC-Master SDK
  • Holoscan operator architecture with periodic scheduling
  • Data flow integration between EtherCAT and Holoscan operators
  • Configurable cycle times and real-time priorities
  • Docker containerization with proper capabilities (in-progress)

Components:

  • HolocatOp: Main EtherCAT operator with state machine management
  • HcDataTxOp: Data transmission operator for counter generation
  • HcDataRxOp: Data reception operator for processing received data

This enables real-time industrial automation applications using EtherCAT fieldbus communication within the Holoscan ecosystem.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added HoloCat application for EtherCAT real-time integration with configurable network adapters, cycle timing, and real-time priorities.
    • Includes EC-Master SDK integration with automated verification and troubleshooting tools.
    • Added Docker containerization support with pre-configured EtherCAT environment.

✏️ Tip: You can customize this high-level summary in your review settings.

Add HoloCat application that integrates EtherCAT real-time
communication with NVIDIA's Holoscan streaming framework.

Key Features:
- Real-time EtherCAT master implementation using EC-Master SDK
- Holoscan operator architecture with periodic scheduling
- Data flow integration between EtherCAT and Holoscan operators
- Configurable cycle times and real-time priorities
- Docker containerization with proper capabilities (in-progress)

Components:
- HolocatOp: Main EtherCAT operator with state machine management
- HcDataTxOp: Data transmission operator for counter generation
- HcDataRxOp: Data reception operator for processing received data
- Comprehensive configuration system with validation
- Build system integration with CMake and Docker

This enables real-time industrial automation applications using
EtherCAT fieldbus communication within the Holoscan ecosystem.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

Walkthrough

Adds a new "holocat" application integrating EtherCAT real-time control with Holoscan. Includes CMake build configuration with conditional EC-Master SDK support, a custom CMake find module, three Holoscan operators for data flow, comprehensive YAML/XML configuration files, Docker containerization, verification scripts, and documentation.

Changes

Cohort / File(s) Summary
Build Configuration
applications/CMakeLists.txt, applications/holocat/CMakeLists.txt, applications/holocat/cpp/CMakeLists.txt
Top-level addition of holocat app entry; conditional CMake build requiring EC-Master SDK with fatal error fallback; C++ project configuration finding holoscan 3.0, setting compiler flags, linking EtherCAT and threading libraries, and optional capabilities setup.
CMake Module
applications/holocat/FindEcMaster.cmake
CMake find module that discovers EC-Master SDK library and headers, constructs imported target EcMaster::EcMaster, extracts version from EcVersion.h, and exposes standard find_package variables.
Operator Implementation
applications/holocat/cpp/hc_data_tx_op.hpp, applications/holocat/cpp/hc_data_tx_op.cpp, applications/holocat/cpp/hc_data_rx_op.hpp, applications/holocat/cpp/hc_data_rx_op.cpp
Simple data transmission and reception operators; TX emits incrementing counter (0–256 wrap), RX receives and logs count values.
EtherCAT Operator
applications/holocat/cpp/holocat_op.hpp, applications/holocat/cpp/holocat_op.cpp
Core EtherCAT operator with asynchronous state machine (INIT → CONFIGURE_NETWORK → GET_PD_MEMORY_SIZE → SET_MASTER_INIT/PREOP/OP → OPERATIONAL), lifecycle hooks (setup/start/stop), logging bridge to EC-Master, compute loop executing EtherCAT jobs, and process image I/O handling.
Application Setup
applications/holocat/cpp/holocat_app.hpp, applications/holocat/cpp/holocat_app.cpp, applications/holocat/cpp/main.cpp
Application class orchestrating operator composition and data flows; configuration extraction and validation (adapter, ENI file, cycle time, priorities with defaults); command-line argument parsing and config file loading in main.
Configuration Files
applications/holocat/configs/holocat_config.yaml, applications/holocat/configs/eni2.xml
YAML declaring adapter_name, eni_file, cycle_time_us, RT priorities, DIO offsets, and Holoscan logging; XML defining EtherCAT master, two slave devices, process data mappings, and state machine.
Container & Documentation
applications/holocat/Dockerfile, applications/holocat/README.md, applications/holocat/scripts/verify_ecmaster.sh
Docker image installing EtherCAT dependencies, deploying EC-Master SDK, creating holocat user with sudo/setcap privileges, and verification script; README with usage, config examples, and troubleshooting; shell script validating SDK installation and system requirements.
Metadata
applications/holocat/metadata.json
Application metadata including name, authors, version, holoscan SDK requirements, supported platforms, and run configurations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Extra attention areas:
    • holocat_op.cpp/hpp: Complex asynchronous state machine with EtherCAT lifecycle management, job threading, and process image I/O; verify state transitions, error handling, and thread safety
    • FindEcMaster.cmake: CMake module with imported target configuration; validate SDK discovery logic, library/include path detection, and version extraction
    • holocat_app.cpp: Configuration extraction and validation logic; ensure ENI file checks, cycle time range enforcement, and defaults are correct
    • Dockerfile: Multi-step setup with capability assignment; verify SDK deployment path, environment variables, and fallback verification logic

Suggested reviewers

  • bhashemian
  • jjomier
  • tbirdso

Pre-merge checks

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(holocat): Add EtherCAT application' directly and clearly summarizes the main change: introducing a new HoloCat application with EtherCAT integration.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 17

🧹 Nitpick comments (15)
applications/holocat/README.md (1)

26-26: Replace hardcoded path with placeholder.

The ECMASTER_ROOT path is user-specific and should use a placeholder instead.

Apply this diff:

-export ECMASTER_ROOT=/home/hking/devel/ethercat/ecm
+export ECMASTER_ROOT=/path/to/ec-master-sdk
applications/holocat/cpp/hc_data_rx_op.hpp (1)

19-20: Clarify data source in documentation.

The documentation states the operator "receives integer data from the ECat bus," but based on the operator architecture, it actually receives data from another Holoscan operator (HolocatOp). Consider clarifying the data flow.

Example:

- * A Holoscan operator that receives integer data from the ECat bus.
- * This operator acts as a data receiver, receiving integer values from the ECat bus.
+ * A Holoscan operator that receives integer data from the HolocatOp.
+ * This operator acts as a data receiver in the Holocat data flow pipeline.
applications/holocat/configs/holocat_config.yaml (2)

5-5: Use generic adapter name in example configuration.

The adapter name appears to be a specific hardware MAC-based identifier. For an example configuration file, use a more generic placeholder.

Apply this diff:

-  adapter_name: "enxc84bd6d2788c"
+  adapter_name: "eth0"  # Change to your EtherCAT interface

Note: This matches the placeholder used in the README example.


9-9: Replace hardcoded path with relative or placeholder path.

The ENI file path contains a user-specific absolute path. Use a relative path or generic placeholder.

Apply this diff:

-  eni_file: "/home/hking/devel/holo/holohub/applications/holocat/configs/eni2.xml"
+  eni_file: "applications/holocat/configs/eni2.xml"

Or use an environment variable placeholder as suggested in the comment above.

applications/holocat/CMakeLists.txt (1)

1-30: Add testing section for functional tests.

Per coding guidelines, applications should include a testing section in CMakeLists.txt for functional testing using CTest.

As per coding guidelines, applications should include testing.

Consider adding after the add_subdirectory(cpp) line:

# Testing
if(BUILD_TESTING)
    add_subdirectory(tests)
endif()
applications/holocat/configs/eni2.xml (1)

1-1: Document the example ENI configuration.

This ENI file appears to be for specific hardware (simco drive 40028083-00-0 and WAGO 750-354). Consider adding a comment or separate README in the configs directory explaining that this is an example configuration and users must generate their own ENI file for their specific EtherCAT hardware setup.

Consider adding applications/holocat/configs/README.md:

# EtherCAT Configuration Files

## eni2.xml

This is an example EtherCAT Network Information (ENI) file for:
- SubDevice_1001: simco drive 40028083-00-0
- SubDevice_1002: WAGO 750-354 I/O module

**Important**: You must generate your own ENI file matching your specific EtherCAT hardware configuration using EtherCAT configuration tools (e.g., TwinCAT, EC-Engineer, or acontis EC-Engineer).
applications/holocat/cpp/CMakeLists.txt (1)

1-89: Missing CTest integration for functional testing.

Per coding guidelines, applications should include a testing section in CMakeLists.txt for functional testing using CTest.

Consider adding a testing section:

# Testing
if(BUILD_TESTING)
    enable_testing()
    # Add test cases here
endif()
applications/holocat/cpp/hc_data_tx_op.cpp (1)

28-30: Counter starts at 1, not 0.

The counter increments before use, so the first emitted value is 1, not 0. If starting at 0 is intended, consider swapping the order:

-  // Increment counter
-  counter_++;
-  counter_ = counter_ % kMaxCount;
-
   // Emit current counter value
   op_output.emit<int>(counter_, "count_out");
+
+  // Increment counter for next cycle
+  counter_ = (counter_ + 1) % kMaxCount;
applications/holocat/cpp/hc_data_rx_op.cpp (1)

33-34: INFO-level logging on every cycle may be excessive.

In a real-time system with fast cycle times, logging at INFO level on every received value will flood logs and potentially impact performance. Consider using DEBUG level similar to HcDataTxOp.

   last_count_ = maybe_count.value();
-  HOLOSCAN_LOG_INFO("HcDataRxOp: Received count: {}", last_count_);
+  // Log periodically to avoid spam
+  if (last_count_ % 50 == 0) {
+    HOLOSCAN_LOG_DEBUG("HcDataRxOp: 50x Received count = {}", last_count_);
+  }
applications/holocat/cpp/holocat_op.cpp (3)

175-182: Blocking sleep(1) in stop() delays shutdown.

Using sleep(1) blocks the calling thread unconditionally. Consider using a non-blocking approach or reducing the delay if waiting for async completion.

     pending_state_transition_ = std::async(std::launch::async, [this]() {
         return ecatSetMasterState(kEthercatStateChangeTimeout_, eEcatState_INIT);
     });
 
-    sleep(1);
+    // Wait for state transition to complete with timeout
+    if (pending_state_transition_.wait_for(std::chrono::seconds(5)) == std::future_status::timeout) {
+        HOLOSCAN_LOG_WARN("State transition to INIT timed out during stop");
+    }
+
     // deinitialize master
     ecatDeinitMaster();

350-364: Static local variable in compute() is not thread-safe.

The static struct timespec t_last is shared across all invocations. If multiple HolocatOp instances run concurrently or the operator is restarted, timing calculations will be incorrect.

Consider making t_last a member variable initialized in start():

+// In class declaration (holocat_op.hpp):
+  struct timespec t_last_{};
+
+// In start():
+  clock_gettime(CLOCK_MONOTONIC, &t_last_);
+
 // In compute():
     struct timespec t_now;
     clock_gettime(CLOCK_MONOTONIC, &t_now);     
-    static struct timespec t_last{t_now.tv_sec, t_now.tv_nsec};
     ...
-    t_last = t_now;
+    t_last_ = t_now;

311-347: EtherCAT job results are silently discarded.

The return values from ecatExecJob calls are assigned to dwRes but then immediately suppressed with EC_UNREFPARM. While this may be intentional for polling mode, consider logging errors at DEBUG level to aid troubleshooting.

     dwRes = ecatExecJob(eUsrJob_ProcessAllRxFrames, EC_NULL);
-    EC_UNREFPARM(dwRes);
+    if (dwRes != EC_E_NOERROR) {
+        HOLOSCAN_LOG_DEBUG("ProcessAllRxFrames returned: {} (0x{:x})", ecatGetText(dwRes), dwRes);
+    }
applications/holocat/cpp/holocat_app.cpp (2)

72-78: Clarify comment about uninitialized values.

The comment "target remains uninitialized" is misleading since HolocatConfig config = {} value-initializes all members (empty strings, zeros, false). The behavior is correct but the comment should reflect the actual semantics.

   auto try_extract = [this](const std::string& key, auto& target) {
     try {
       target = from_config(key).as<std::decay_t<decltype(target)>>();
     } catch (...) {
-      // Key not found or conversion failed - target remains uninitialized
+      // Key not found or conversion failed - target retains default value
     }
   };

42-47: Consider making the counter update period configurable.

The 100ms period for HcDataTxOp is hardcoded. For flexibility, consider adding this as a configuration parameter similar to cycle_time_us.

applications/holocat/cpp/holocat_op.hpp (1)

10-11: Consider using conventional include guard naming.

The include guard INC_HOLOCAT_H with value 1 is unconventional. A more standard pattern would match the filename.

-#ifndef INC_HOLOCAT_H
-#define INC_HOLOCAT_H 1
+#ifndef HOLOCAT_OP_HPP
+#define HOLOCAT_OP_HPP

And update the closing guard:

-#endif /* INC_HOLOCAT_H */
+#endif  // HOLOCAT_OP_HPP
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42a23cd and 4cc9b7b.

📒 Files selected for processing (19)
  • applications/CMakeLists.txt (1 hunks)
  • applications/holocat/CMakeLists.txt (1 hunks)
  • applications/holocat/Dockerfile (1 hunks)
  • applications/holocat/FindEcMaster.cmake (1 hunks)
  • applications/holocat/README.md (1 hunks)
  • applications/holocat/configs/eni2.xml (1 hunks)
  • applications/holocat/configs/holocat_config.yaml (1 hunks)
  • applications/holocat/cpp/CMakeLists.txt (1 hunks)
  • applications/holocat/cpp/hc_data_rx_op.cpp (1 hunks)
  • applications/holocat/cpp/hc_data_rx_op.hpp (1 hunks)
  • applications/holocat/cpp/hc_data_tx_op.cpp (1 hunks)
  • applications/holocat/cpp/hc_data_tx_op.hpp (1 hunks)
  • applications/holocat/cpp/holocat_app.cpp (1 hunks)
  • applications/holocat/cpp/holocat_app.hpp (1 hunks)
  • applications/holocat/cpp/holocat_op.cpp (1 hunks)
  • applications/holocat/cpp/holocat_op.hpp (1 hunks)
  • applications/holocat/cpp/main.cpp (1 hunks)
  • applications/holocat/metadata.json (1 hunks)
  • applications/holocat/scripts/verify_ecmaster.sh (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
{operators,applications,workflows,gxf_extensions}/**/*.{py,cpp,hpp}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

{operators,applications,workflows,gxf_extensions}/**/*.{py,cpp,hpp}: All code must adhere to Holoscan SDK coding standards including proper error handling and validation
Use descriptive English naming for functions, variables, and components; minimize acronyms and brand names
Include inline comments for complex logic in code

Files:

  • applications/holocat/cpp/hc_data_rx_op.hpp
  • applications/holocat/cpp/hc_data_tx_op.hpp
  • applications/holocat/cpp/main.cpp
  • applications/holocat/cpp/holocat_op.cpp
  • applications/holocat/cpp/holocat_op.hpp
  • applications/holocat/cpp/holocat_app.cpp
  • applications/holocat/cpp/hc_data_tx_op.cpp
  • applications/holocat/cpp/hc_data_rx_op.cpp
  • applications/holocat/cpp/holocat_app.hpp
{operators,applications,workflows,gxf_extensions}/**/*.{py,cpp,hpp,cmake}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

All code must compile and build successfully on target platforms before submission

Files:

  • applications/holocat/cpp/hc_data_rx_op.hpp
  • applications/holocat/cpp/hc_data_tx_op.hpp
  • applications/holocat/cpp/main.cpp
  • applications/holocat/cpp/holocat_op.cpp
  • applications/holocat/cpp/holocat_op.hpp
  • applications/holocat/cpp/holocat_app.cpp
  • applications/holocat/cpp/hc_data_tx_op.cpp
  • applications/holocat/cpp/hc_data_rx_op.cpp
  • applications/holocat/cpp/holocat_app.hpp
  • applications/holocat/FindEcMaster.cmake
{operators,applications,workflows,gxf_extensions,tutorials}/**/README.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

README.md must include purpose, usage instructions, requirements, examples, and architecture overview

Files:

  • applications/holocat/README.md
**/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use Holoscan SDK glossary terms when referring to HoloHub-specific locations in documentation

Files:

  • applications/holocat/README.md
**/metadata.json

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

When reviewing PRs that modify or add metadata.json files, verify that the category (first tag in the tags array) matches one of the approved categories: Benchmarking, Camera, Computer Vision and Perception, Converter, Deployment, Development, Extended Reality, Healthcare AI, Image Processing, Inference, Interoperability, Medical Imaging, Natural Language and Conversational AI, Networking and Distributed Computing, Optimization, Quantum Computing, Rendering, Robotics, Scheduler, Signal Processing, Streaming, Threading, Video, Video Capture, Visualization, XR

**/metadata.json: Use interface or specific metadata schema for defining contribution structure (metadata.json)
metadata.json must include name, authors, language, version, changelog, holoscan_sdk info, platforms, tags, ranking, dependencies, and run command
metadata.json ranking levels must be self-assessed from 0 (production-ready) to 5 (deprecated) with corresponding requirements
Dependencies must be correctly specified in metadata.json dependencies section

Files:

  • applications/holocat/metadata.json
{applications,workflows}/**/CMakeLists.txt

📄 CodeRabbit inference engine (CONTRIBUTING.md)

CMakeLists.txt must include build system integration using add_holohub_application() for applications and workflows

Files:

  • applications/holocat/CMakeLists.txt
  • applications/CMakeLists.txt
  • applications/holocat/cpp/CMakeLists.txt
applications/**/CMakeLists.txt

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Applications should include a testing section in CMakeLists.txt for functional testing using CTest

Files:

  • applications/holocat/CMakeLists.txt
  • applications/CMakeLists.txt
  • applications/holocat/cpp/CMakeLists.txt
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.280Z
Learning: Applies to operators/**/CMakeLists.txt : CMakeLists.txt must include build system integration using add_holohub_operator() for operators
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.280Z
Learning: Applies to {applications,workflows}/**/CMakeLists.txt : CMakeLists.txt must include build system integration using add_holohub_application() for applications and workflows
Learnt from: cdinea
Repo: nvidia-holoscan/holohub PR: 1170
File: operators/video_streaming/streaming_client_enhanced/python/CMakeLists.txt:16-24
Timestamp: 2025-10-22T16:53:45.393Z
Learning: The pybind11_add_holohub_module CMake macro in cmake/pybind11_add_holohub_module.cmake encapsulates all pybind11 setup internally, including finding pybind11, linking against holoscan::pybind11 conditionally, and linking the C++ operator target. Operator Python bindings in holohub should only call this macro without additional pybind11 setup.
📚 Learning: 2025-11-24T16:28:06.280Z
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.280Z
Learning: Applies to operators/**/CMakeLists.txt : CMakeLists.txt must include build system integration using add_holohub_operator() for operators

Applied to files:

  • applications/holocat/cpp/hc_data_rx_op.hpp
  • applications/holocat/cpp/hc_data_tx_op.hpp
  • applications/holocat/CMakeLists.txt
  • applications/CMakeLists.txt
  • applications/holocat/cpp/holocat_op.hpp
  • applications/holocat/cpp/hc_data_tx_op.cpp
  • applications/holocat/cpp/hc_data_rx_op.cpp
  • applications/holocat/cpp/CMakeLists.txt
📚 Learning: 2025-11-24T16:28:06.280Z
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.280Z
Learning: Applies to {operators,applications,workflows,gxf_extensions}/**/*.{py,cpp,hpp} : All code must adhere to Holoscan SDK coding standards including proper error handling and validation

Applied to files:

  • applications/holocat/cpp/hc_data_rx_op.hpp
  • applications/holocat/cpp/holocat_op.hpp
  • applications/holocat/cpp/holocat_app.cpp
  • applications/holocat/cpp/hc_data_rx_op.cpp
📚 Learning: 2025-11-24T16:28:06.281Z
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.281Z
Learning: Applies to **/metadata.json : metadata.json must include name, authors, language, version, changelog, holoscan_sdk info, platforms, tags, ranking, dependencies, and run command

Applied to files:

  • applications/holocat/metadata.json
📚 Learning: 2025-11-24T16:27:43.600Z
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T16:27:43.600Z
Learning: Applies to **/metadata.json : When reviewing PRs that modify or add `metadata.json` files, verify that the **category** (first tag in the `tags` array) matches one of the approved categories: Benchmarking, Camera, Computer Vision and Perception, Converter, Deployment, Development, Extended Reality, Healthcare AI, Image Processing, Inference, Interoperability, Medical Imaging, Natural Language and Conversational AI, Networking and Distributed Computing, Optimization, Quantum Computing, Rendering, Robotics, Scheduler, Signal Processing, Streaming, Threading, Video, Video Capture, Visualization, XR

Applied to files:

  • applications/holocat/metadata.json
📚 Learning: 2025-11-24T16:28:06.280Z
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.280Z
Learning: Applies to {applications,workflows}/**/CMakeLists.txt : CMakeLists.txt must include build system integration using add_holohub_application() for applications and workflows

Applied to files:

  • applications/holocat/CMakeLists.txt
  • applications/CMakeLists.txt
  • applications/holocat/cpp/CMakeLists.txt
📚 Learning: 2025-11-24T16:28:06.280Z
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.280Z
Learning: Applies to gxf_extensions/**/CMakeLists.txt : CMakeLists.txt must include build system integration using add_holohub_extension() for GXF extensions

Applied to files:

  • applications/holocat/CMakeLists.txt
  • applications/CMakeLists.txt
  • applications/holocat/cpp/CMakeLists.txt
📚 Learning: 2025-11-24T16:28:06.280Z
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.280Z
Learning: Applies to applications/**/CMakeLists.txt : Applications should include a testing section in CMakeLists.txt for functional testing using CTest

Applied to files:

  • applications/holocat/CMakeLists.txt
  • applications/CMakeLists.txt
📚 Learning: 2025-11-24T16:28:06.281Z
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.281Z
Learning: Applies to applications/**/ : Applications should follow the directory structure with metadata.json, README.md, implementation files, and CMakeLists.txt

Applied to files:

  • applications/holocat/CMakeLists.txt
  • applications/CMakeLists.txt
📚 Learning: 2025-10-22T16:53:45.393Z
Learnt from: cdinea
Repo: nvidia-holoscan/holohub PR: 1170
File: operators/video_streaming/streaming_client_enhanced/python/CMakeLists.txt:16-24
Timestamp: 2025-10-22T16:53:45.393Z
Learning: The pybind11_add_holohub_module CMake macro in cmake/pybind11_add_holohub_module.cmake encapsulates all pybind11 setup internally, including finding pybind11, linking against holoscan::pybind11 conditionally, and linking the C++ operator target. Operator Python bindings in holohub should only call this macro without additional pybind11 setup.

Applied to files:

  • applications/CMakeLists.txt
📚 Learning: 2025-11-24T16:28:06.280Z
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.280Z
Learning: Each operator should have at least one associated application demonstrating its capabilities

Applied to files:

  • applications/CMakeLists.txt
📚 Learning: 2025-11-24T16:28:06.280Z
Learnt from: CR
Repo: nvidia-holoscan/holohub PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T16:28:06.280Z
Learning: Applies to operators/**/*.{py,cpp,hpp} : Use TitleCase + 'Op' suffix for operator class names

Applied to files:

  • applications/holocat/cpp/holocat_op.hpp
🧬 Code graph analysis (3)
applications/holocat/cpp/hc_data_rx_op.hpp (2)
applications/holocat/cpp/hc_data_tx_op.hpp (2)
  • spec (40-40)
  • op_input (48-50)
applications/holocat/cpp/holocat_op.hpp (2)
  • spec (63-63)
  • op_input (65-67)
applications/holocat/cpp/hc_data_tx_op.hpp (2)
applications/holocat/cpp/hc_data_rx_op.hpp (2)
  • spec (38-38)
  • op_input (46-48)
applications/holocat/cpp/holocat_op.hpp (2)
  • spec (63-63)
  • op_input (65-67)
applications/holocat/cpp/holocat_op.hpp (3)
applications/holocat/cpp/holocat_app.hpp (1)
  • config (25-25)
applications/holocat/cpp/hc_data_rx_op.hpp (2)
  • spec (38-38)
  • op_input (46-48)
applications/holocat/cpp/hc_data_tx_op.hpp (2)
  • spec (40-40)
  • op_input (48-50)
🪛 Cppcheck (2.18.0)
applications/holocat/cpp/main.cpp

[error] 55-55: There is an unknown macro here somewhere. Configuration is required. If HOLOSCAN_OPERATOR_FORWARD_ARGS is a macro then please configure it.

(unknownMacro)

applications/holocat/cpp/holocat_op.cpp

[error] 55-55: There is an unknown macro here somewhere. Configuration is required. If HOLOSCAN_OPERATOR_FORWARD_ARGS is a macro then please configure it.

(unknownMacro)

applications/holocat/cpp/holocat_app.cpp

[error] 55-55: There is an unknown macro here somewhere. Configuration is required. If HOLOSCAN_OPERATOR_FORWARD_ARGS is a macro then please configure it.

(unknownMacro)

🔇 Additional comments (14)
applications/CMakeLists.txt (1)

152-152: LGTM!

The holocat application is correctly integrated using add_holohub_application() and positioned in proper alphabetical order.

As per coding guidelines, CMakeLists.txt correctly uses add_holohub_application().

applications/holocat/cpp/holocat_app.hpp (1)

1-28: LGTM!

The application class is properly structured, inheriting from holoscan::Application with appropriate method declarations for configuration extraction and validation.

applications/holocat/cpp/hc_data_tx_op.cpp (1)

17-22: LGTM!

The setup method correctly configures the output port with appropriate logging.

applications/holocat/scripts/verify_ecmaster.sh (1)

1-221: Well-structured verification script.

Comprehensive SDK validation covering directory structure, libraries, version extraction, and system requirements. The colored output and clear next steps guidance are helpful.

applications/holocat/cpp/main.cpp (1)

54-74: LGTM!

Clean argument parsing with proper error handling for missing values and unknown options.

applications/holocat/cpp/holocat_op.cpp (1)

32-59: LGTM!

The logging bridge correctly maps EC-Master severity levels to Holoscan logging with appropriate prefixing.

applications/holocat/Dockerfile (2)

29-31: User permissions are appropriately configured.

The holocat user creation with scoped NOPASSWD access for setcap is appropriate for granting real-time capabilities to the application without requiring full root access during normal operation.


45-49: Verification fallback logic is sensible.

The approach of running the full verification script with a fallback to minimal SDK checks (header and library existence) provides build resilience while still ensuring essential components are present.

applications/holocat/FindEcMaster.cmake (2)

123-137: Imported target is correctly defined.

The EcMaster::EcMaster imported target follows CMake conventions with proper interface properties for include directories and link libraries.


1-16: Well-structured CMake find module.

Good use of policy handling for CMP0144 (environment variable handling) and clear documentation of the module's outputs.

applications/holocat/cpp/holocat_app.cpp (1)

140-154: Priority validation handles defaults correctly.

The validation properly detects zero-initialized priorities (from missing config) and applies sensible defaults with appropriate warning logs.

applications/holocat/cpp/holocat_op.hpp (3)

24-38: Configuration struct is well-organized.

The HolocatConfig struct clearly groups related configuration parameters. Including error_message for validation feedback is a pragmatic approach.


53-68: Operator class follows Holoscan conventions.

The HolocatOp class correctly derives from holoscan::Operator, uses the HOLOSCAN_OPERATOR_FORWARD_ARGS macro for constructor forwarding, and follows the TitleCase + 'Op' naming convention per coding guidelines.


105-118: Async state transition design is appropriate for real-time operation.

Using std::future for pending state transitions allows the operator to maintain real-time scheduling while managing the EtherCAT state machine asynchronously.

Comment on lines +26 to +30
message(FATAL_ERROR "EC-Master SDK not found")

# Exit with failure
exit(1)
endif()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove invalid exit() command.

exit(1) is not a valid CMake command. The message(FATAL_ERROR ...) on line 26 already halts CMake configuration, making line 29 unreachable and incorrect.

Apply this diff:

 else()
     message(FATAL_ERROR "EC-Master SDK not found")
-
-    # Exit with failure
-    exit(1)
 endif()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
message(FATAL_ERROR "EC-Master SDK not found")
# Exit with failure
exit(1)
endif()
else()
message(FATAL_ERROR "EC-Master SDK not found")
endif()
🤖 Prompt for AI Agents
In applications/holocat/CMakeLists.txt around lines 26 to 30, remove the invalid
exit(1) call since CMake does not have exit() and message(FATAL_ERROR "EC-Master
SDK not found") already stops configuration; simply delete the exit(1) line so
the FATAL_ERROR stands alone and there is no unreachable/incorrect command.

Comment on lines +47 to +48
# Create executable
add_executable(holocat ${HOLOCAT_SOURCES} ${HOLOCAT_HEADERS})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Missing add_holohub_application() build system integration.

Per HoloHub coding guidelines, applications must use add_holohub_application() for proper build system integration instead of raw add_executable(). This ensures consistent build behavior and integration with the HoloHub infrastructure.

Based on learnings, the CMakeLists.txt should include build system integration using add_holohub_application().

🤖 Prompt for AI Agents
In applications/holocat/cpp/CMakeLists.txt around lines 47-48, the build
currently calls add_executable(holocat ${HOLOCAT_SOURCES} ${HOLOCAT_HEADERS})
which violates HoloHub guidelines; replace this raw add_executable call with the
prescribed add_holohub_application() invocation, passing the same target name
and source/header lists (and any required properties or options the HoloHub
macro expects) so the holocat target is registered through the HoloHub build
integration rather than created directly.

Comment on lines +83 to +89
option(HOLOCAT_SET_CAPABILITIES "Set Linux capabilities during build" ON)
if(HOLOCAT_SET_CAPABILITIES)
add_custom_command(TARGET holocat POST_BUILD
COMMAND sudo setcap 'cap_net_raw,cap_sys_nice,cap_ipc_lock=ep' $<TARGET_FILE:holocat>
COMMENT "Setting capabilities for real-time EtherCAT operation"
)
endif()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

sudo in POST_BUILD will break non-privileged builds.

Using sudo in a CMake post-build command requires interactive authentication and will fail in CI/CD pipelines, containers without sudo, or when users lack sudo access. Consider making this a separate script or installation step rather than part of the build.

-option(HOLOCAT_SET_CAPABILITIES "Set Linux capabilities during build" ON)
+option(HOLOCAT_SET_CAPABILITIES "Set Linux capabilities during build" OFF)
 if(HOLOCAT_SET_CAPABILITIES)
+    message(WARNING "HOLOCAT_SET_CAPABILITIES requires sudo privileges - ensure you have appropriate access")
     add_custom_command(TARGET holocat POST_BUILD
         COMMAND sudo setcap 'cap_net_raw,cap_sys_nice,cap_ipc_lock=ep' $<TARGET_FILE:holocat>
         COMMENT "Setting capabilities for real-time EtherCAT operation"
     )
 endif()

Alternatively, provide a separate install script that users can run manually with appropriate privileges.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
option(HOLOCAT_SET_CAPABILITIES "Set Linux capabilities during build" ON)
if(HOLOCAT_SET_CAPABILITIES)
add_custom_command(TARGET holocat POST_BUILD
COMMAND sudo setcap 'cap_net_raw,cap_sys_nice,cap_ipc_lock=ep' $<TARGET_FILE:holocat>
COMMENT "Setting capabilities for real-time EtherCAT operation"
)
endif()
option(HOLOCAT_SET_CAPABILITIES "Set Linux capabilities during build" OFF)
if(HOLOCAT_SET_CAPABILITIES)
message(WARNING "HOLOCAT_SET_CAPABILITIES requires sudo privileges - ensure you have appropriate access")
add_custom_command(TARGET holocat POST_BUILD
COMMAND sudo setcap 'cap_net_raw,cap_sys_nice,cap_ipc_lock=ep' $<TARGET_FILE:holocat>
COMMENT "Setting capabilities for real-time EtherCAT operation"
)
endif()
🤖 Prompt for AI Agents
In applications/holocat/cpp/CMakeLists.txt around lines 83-89, remove the use of
sudo in the POST_BUILD add_custom_command (it breaks non-privileged/CI builds)
and instead move capability-setting out of the build phase: implement either (a)
an install-time step (e.g. add a CMake install(CODE) or install script that runs
setcap) or (b) a separate optional install target/script (e.g.
add_custom_target(setcap INSTALL_COMMAND ...) or a packaged script in CMake
config) and document that it must be run with appropriate privileges; ensure the
build does not require sudo, optionally add a CMake option to enable automatic
install-time setcap and emit a clear message when capabilities are not set so
users know to run the privileged script.

Comment on lines +1 to +7
/*-----------------------------------------------------------------------------
* hc_data_rx_op.cpp
* HoloCat Data Receive Operator
*
* This file implements the HcDataTxOp operator that generates incrementing
* counter data for testing and demonstration purposes.
*---------------------------------------------------------------------------*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Copy-paste error in file header comment.

The header describes HcDataTxOp but this file implements HcDataRxOp.

 /*-----------------------------------------------------------------------------
  * hc_data_rx_op.cpp
  * HoloCat Data Receive Operator
  * 
- * This file implements the HcDataTxOp operator that generates incrementing
- * counter data for testing and demonstration purposes.
+ * This file implements the HcDataRxOp operator that receives counter
+ * data from the EtherCAT bus for testing and demonstration purposes.
  *---------------------------------------------------------------------------*/
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/*-----------------------------------------------------------------------------
* hc_data_rx_op.cpp
* HoloCat Data Receive Operator
*
* This file implements the HcDataTxOp operator that generates incrementing
* counter data for testing and demonstration purposes.
*---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
* hc_data_rx_op.cpp
* HoloCat Data Receive Operator
*
* This file implements the HcDataRxOp operator that receives counter
* data from the EtherCAT bus for testing and demonstration purposes.
*---------------------------------------------------------------------------*/
🤖 Prompt for AI Agents
In applications/holocat/cpp/hc_data_rx_op.cpp around lines 1 to 7, the file
header comment incorrectly references HcDataTxOp and describes transmitter
behavior; update the header to correctly name HcDataRxOp and describe that this
file implements the HcDataRxOp (the data receive operator) and its purpose
(e.g., receiving/parsing incoming data for HoloCat), ensuring the header text
accurately reflects the implementation and purpose.


/**
* @brief Compute method called on each execution cycle
* @param op_input Input context (unused for this source operator)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix incorrect comment about operator type.

The comment states "unused for this source operator" but HcDataRxOp is a receiver/sink operator, not a source operator.

Apply this diff:

-   * @param op_input Input context (unused for this source operator)
+   * @param op_input Input context for receiving counter data
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* @param op_input Input context (unused for this source operator)
* @param op_input Input context for receiving counter data
🤖 Prompt for AI Agents
In applications/holocat/cpp/hc_data_rx_op.hpp around line 42, the param comment
incorrectly refers to HcDataRxOp as a "source operator"; this operator is a
receiver/sink. Update the comment text for the op_input parameter to reflect the
correct operator type (for example: "op_input Input context (unused for this
receiver/sink operator)" or "unused for this sink operator") so the docstring
accurately describes HcDataRxOp.

Comment on lines +100 to +102
if(ECMASTER_VERSION_MAJOR AND ECMASTER_VERSION_MINOR AND ECMASTER_VERSION_PATCH)
set(ECMASTER_VERSION "${ECMASTER_VERSION_MAJOR}.${ECMASTER_VERSION_MINOR}.${ECMASTER_VERSION_PATCH}.${ECMASTER_VERSION_BUILD}")
endif()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Version string may include empty component if BUILD is not found.

If EC_VERSION_BUILD is not defined in the header, ECMASTER_VERSION_BUILD will be empty, resulting in a version string like "3.2.1." with a trailing dot.

Consider conditionally including the build number:

         if(ECMASTER_VERSION_MAJOR AND ECMASTER_VERSION_MINOR AND ECMASTER_VERSION_PATCH)
-            set(ECMASTER_VERSION "${ECMASTER_VERSION_MAJOR}.${ECMASTER_VERSION_MINOR}.${ECMASTER_VERSION_PATCH}.${ECMASTER_VERSION_BUILD}")
+            if(ECMASTER_VERSION_BUILD)
+                set(ECMASTER_VERSION "${ECMASTER_VERSION_MAJOR}.${ECMASTER_VERSION_MINOR}.${ECMASTER_VERSION_PATCH}.${ECMASTER_VERSION_BUILD}")
+            else()
+                set(ECMASTER_VERSION "${ECMASTER_VERSION_MAJOR}.${ECMASTER_VERSION_MINOR}.${ECMASTER_VERSION_PATCH}")
+            endif()
         endif()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if(ECMASTER_VERSION_MAJOR AND ECMASTER_VERSION_MINOR AND ECMASTER_VERSION_PATCH)
set(ECMASTER_VERSION "${ECMASTER_VERSION_MAJOR}.${ECMASTER_VERSION_MINOR}.${ECMASTER_VERSION_PATCH}.${ECMASTER_VERSION_BUILD}")
endif()
if(ECMASTER_VERSION_MAJOR AND ECMASTER_VERSION_MINOR AND ECMASTER_VERSION_PATCH)
if(ECMASTER_VERSION_BUILD)
set(ECMASTER_VERSION "${ECMASTER_VERSION_MAJOR}.${ECMASTER_VERSION_MINOR}.${ECMASTER_VERSION_PATCH}.${ECMASTER_VERSION_BUILD}")
else()
set(ECMASTER_VERSION "${ECMASTER_VERSION_MAJOR}.${ECMASTER_VERSION_MINOR}.${ECMASTER_VERSION_PATCH}")
endif()
endif()
🤖 Prompt for AI Agents
In applications/holocat/FindEcMaster.cmake around lines 100-102, the version
string unconditionally appends ECMASTER_VERSION_BUILD which can be empty and
yield a trailing dot; change the logic to build a base version from
ECMASTER_VERSION_MAJOR.MINOR.PATCH and then only append
".${ECMASTER_VERSION_BUILD}" if ECMASTER_VERSION_BUILD is defined and not empty
(e.g., check using IF(DEFINED ECMASTER_VERSION_BUILD AND NOT
"${ECMASTER_VERSION_BUILD}" STREQUAL "") or similar) so the final
ECMASTER_VERSION has no trailing dot when build is missing.

Comment on lines +25 to +27
"tags": [
"EtherCAT"
],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Invalid category tag - use approved category.

The first tag in the tags array serves as the category and must be from the approved list. "EtherCAT" is not an approved category. Based on the application's purpose, consider using "Interoperability" or "Networking and Distributed Computing".

As per coding guidelines, the category must match one of the approved categories.

Apply this diff to use an appropriate category:

 		"tags": [
-			"EtherCAT"
+			"Interoperability",
+			"EtherCAT"
 		],

Or if networking focus is more appropriate:

 		"tags": [
-			"EtherCAT"
+			"Networking and Distributed Computing",
+			"EtherCAT"
 		],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"tags": [
"EtherCAT"
],
"tags": [
"Interoperability",
"EtherCAT"
],
Suggested change
"tags": [
"EtherCAT"
],
"tags": [
"Networking and Distributed Computing",
"EtherCAT"
],
🤖 Prompt for AI Agents
In applications/holocat/metadata.json around lines 25 to 27, the first element
of the "tags" array ("EtherCAT") is not an approved category; replace it with an
approved category that reflects the app purpose — e.g. change the first tag to
"Interoperability" (or "Networking and Distributed Computing" if networking is
more accurate) so the tags[0] matches the approved category list and keep any
additional tags after it.

Comment on lines +1 to +94
# HoloCat - EtherCAT Real-time Integration

![HoloCat Logo](docs/holocat_logo.png)

HoloCat is an EtherCAT master application that integrates the acontis EC-Master SDK with NVIDIA's Holoscan platform.

## Overview

HoloCat provides deterministic EtherCAT communication capabilities within the Holoscan ecosystem, enabling:

- **Real-time Control**
- **Holoscan Native**

## Prerequisites

### Required Dependencies

1. **acontis EC-Master SDK** (Commercial License)
- Version 3.2.3 or later

## Usage

### Prerequisites
```bash
# Set EC-Master SDK path
export ECMASTER_ROOT=/home/hking/devel/ethercat/ecm

# Verify installation (optional)
./applications/holocat/scripts/verify_ecmaster.sh
```

### Build
```bash
# Build using HoloHub CLI (recommended)
./holohub build holocat --local
```

### Run
```bash
# Run with configuration file
./build/holocat/applications/holocat/cpp/holocat --config ./applications/holocat/configs/holocat_config.yaml
```

## Configuration

### Basic Configuration

Create `holocat_config.yaml`:

```yaml
holocat:
# Network adapter for EtherCAT
adapter_name: "eth0" # Change to your EtherCAT interface

# EtherCAT configuration file
eni_file: "/tmp/holocat_config.xml"

# Cycle time in microseconds
cycle_time_us: 1000 # 1ms cycle time

# Real-time priorities (1-99)
rt_priority: 39
job_thread_priority: 98

# Enable real-time scheduling
enable_rt: true

# Holoscan application configuration
holoscan:
logging:
level: "info"
```

### ENI File Generation

Use EtherCAT configuration tools to generate your ENI file.


## Troubleshooting

### Common Issues

1. **Permission Denied**
```bash
# Ensure capabilities are set
sudo setcap 'cap_net_raw=ep' ./build/holocat/applications/holocat/holocat
```

3. **EC-Master SDK Not Found**
```bash
# Verify ECMASTER_ROOT environment variable
echo $ECMASTER_ROOT
ls -la $ECMASTER_ROOT/SDK/INC/EcMaster.h
``` No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add architecture overview section.

Per coding guidelines, the README should include an architecture overview. Add a section explaining the operator architecture (HolocatOp, HcDataTxOp, HcDataRxOp) and how they interact with the EtherCAT master and Holoscan framework.

As per coding guidelines, README.md must include architecture overview.

🤖 Prompt for AI Agents
applications/holocat/README.md lines 1-94: The README lacks the required
"Architecture Overview" section; add a concise subsection titled "Architecture
Overview" describing the operator architecture: list and briefly describe
HolocatOp, HcDataTxOp, and HcDataRxOp, explain that HolocatOp manages lifecycle
and interfaces with the acontis EC‑Master SDK (initialization, ENI loading,
cycle scheduling), HcDataTxOp handles outgoing process data to EtherCAT slaves
and timing control, and HcDataRxOp handles incoming process data and publishes
to Holoscan; include a simple diagram or sequence description of how data flows
between Holoscan application -> HolocatOp -> (HcDataTxOp -> EtherCAT master ->
slaves) and (slaves -> EtherCAT master -> HcDataRxOp -> Holoscan), and mention
real‑time considerations (cycle timing and priorities) and configuration points
(adapter_name, eni_file, cycle_time_us).

Comment on lines +83 to +89
1. **Permission Denied**
```bash
# Ensure capabilities are set
sudo setcap 'cap_net_raw=ep' ./build/holocat/applications/holocat/holocat
```

3. **EC-Master SDK Not Found**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix troubleshooting section numbering.

The numbering jumps from issue 1 to issue 3, skipping 2.

Apply this diff:

-3. **EC-Master SDK Not Found**
+2. **EC-Master SDK Not Found**
🤖 Prompt for AI Agents
In applications/holocat/README.md around lines 83 to 89, the troubleshooting
list numbering skips from "1. Permission Denied" to "3. EC-Master SDK Not
Found"; update the ordered list so entries are sequential (1, 2, 3) by
renumbering the affected items or converting to an auto-numbered markdown list
so the second issue becomes "2. EC-Master SDK Not Found" (or use a continuous
numbered sequence) to restore correct ordering and consistency.

Comment on lines +111 to +118
for lib in "${LINK_LIBS[@]}"; do
if [ -f "$LIB_DIR/$lib" ]; then
print_status "OK" "$lib found"
((FOUND_LIBS++))
else
print_status "WARN" "$lib not found (may be optional)"
fi
done
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Arithmetic increment may cause premature exit with set -e.

When FOUND_LIBS is 0, the expression ((FOUND_LIBS++)) evaluates to 0 (falsy), which bash treats as a failure. Combined with set -e, this will exit the script prematurely on the first found library.

     if [ -f "$LIB_DIR/$lib" ]; then
         print_status "OK" "$lib found"
-        ((FOUND_LIBS++))
+        FOUND_LIBS=$((FOUND_LIBS + 1))
     else
         print_status "WARN" "$lib not found (may be optional)"
     fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for lib in "${LINK_LIBS[@]}"; do
if [ -f "$LIB_DIR/$lib" ]; then
print_status "OK" "$lib found"
((FOUND_LIBS++))
else
print_status "WARN" "$lib not found (may be optional)"
fi
done
for lib in "${LINK_LIBS[@]}"; do
if [ -f "$LIB_DIR/$lib" ]; then
print_status "OK" "$lib found"
FOUND_LIBS=$((FOUND_LIBS + 1))
else
print_status "WARN" "$lib not found (may be optional)"
fi
done
🤖 Prompt for AI Agents
In applications/holocat/scripts/verify_ecmaster.sh around lines 111-118, the use
of the post-increment expression ((FOUND_LIBS++)) can produce a zero exit status
when FOUND_LIBS is 0 and cause the script to exit under set -e; change the
increment to a form that yields a non-zero arithmetic result (for example use
FOUND_LIBS=$((FOUND_LIBS+1)) or ((FOUND_LIBS+=1))) so the operation does not
return a failing status and the loop won't prematurely exit.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 9, 2025

Greptile Summary

  • Adds new HoloCat application that integrates EtherCAT real-time industrial communication with Holoscan's streaming framework using EC-Master SDK
  • Implements three-operator pipeline architecture: HcDataTxOp (counter generation) → HolocatOp (EtherCAT communication) → HcDataRxOp (data reception)
  • Provides Docker containerization, CMake build system integration, comprehensive configuration management, and automated SDK verification tooling

Important Files Changed

Filename Overview
applications/holocat/cpp/holocat_op.cpp New EtherCAT master operator; contains buffer overflow risk in LogMsgCallback function and unreachable code after exception
applications/holocat/Dockerfile New Docker configuration; has undefined variable BASE_IMAGE that will cause build failure
applications/holocat/CMakeLists.txt New build configuration; includes unreachable code after FATAL_ERROR statement
applications/holocat/cpp/CMakeLists.txt Build system for C++ components; executes sudo setcap during build process which poses security considerations

Confidence score: 3/5

  • This PR requires careful review due to several code issues including buffer overflow risks, undefined variables, and unreachable code blocks
  • Score reflects multiple technical issues: buffer overflow in logging callback (security risk), undefined Docker variable (build failure), unreachable code after exceptions, and sudo execution during build (security consideration)
  • Pay close attention to applications/holocat/cpp/holocat_op.cpp for the buffer overflow fix and applications/holocat/Dockerfile for the BASE_IMAGE variable definition

Sequence Diagram

sequenceDiagram
    participant User
    participant HolocatApp as "HolocatApp"
    participant HcDataTxOp as "HcDataTxOp"
    participant HolocatOp as "HolocatOp"
    participant EtherCAT as "EtherCAT Master"
    participant HcDataRxOp as "HcDataRxOp"

    User->>HolocatApp: "run()"
    HolocatApp->>HolocatApp: "compose()"
    HolocatApp->>HcDataTxOp: "create operator"
    HolocatApp->>HolocatOp: "create operator"
    HolocatApp->>HcDataRxOp: "create operator"
    HolocatApp->>HolocatOp: "start()"
    HolocatOp->>EtherCAT: "ecatInitMaster()"
    
    loop "Periodic Execution"
        HcDataTxOp->>HcDataTxOp: "compute()"
        HcDataTxOp->>HolocatOp: "count_out"
        HolocatOp->>HolocatOp: "compute()"
        HolocatOp->>EtherCAT: "ecatExecJob(ProcessAllRxFrames)"
        HolocatOp->>EtherCAT: "ecatGetProcessImageInputPtr()"
        EtherCAT-->>HolocatOp: "process data"
        HolocatOp->>EtherCAT: "ecatGetProcessImageOutputPtr()"
        HolocatOp->>EtherCAT: "write process data"
        HolocatOp->>EtherCAT: "ecatExecJob(SendAllCycFrames)"
        HolocatOp->>HcDataRxOp: "count_out"
        HcDataRxOp->>HcDataRxOp: "compute()"
    end
    
    User->>HolocatApp: "stop()"
    HolocatOp->>HolocatOp: "stop()"
    HolocatOp->>EtherCAT: "ecatSetMasterState(INIT)"
    HolocatOp->>EtherCAT: "ecatDeinitMaster()"
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (2)

  1. applications/holocat/Dockerfile, line 3-4 (link)

    syntax: BASE_IMAGE is used but never defined. The ARG declares BASE_SDK_VERSION but the FROM uses ${BASE_IMAGE}. This will cause the Docker build to fail.

  2. applications/holocat/CMakeLists.txt, line 26-30 (link)

    syntax: Unreachable code. message(FATAL_ERROR ...) already terminates CMake execution, so exit(1) will never run.

19 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@bhashemian bhashemian requested a review from a team December 9, 2025 19:48
@bhashemian
Copy link
Member

Hi @hawkeyeking, thanks for this contribution. There are a few comments from the AI reviewer, which worth checking if not relevant please make the resolve with a short comment. Once they are addressed, we'd be happy to do the full review. Thaks

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (3)

  1. applications/holocat/CMakeLists.txt, line 26-29 (link)

    logic: Unreachable code - message(FATAL_ERROR ...) terminates CMake execution immediately, so exit(1) will never run.

  2. applications/holocat/Dockerfile, line 3-4 (link)

    syntax: BASE_IMAGE is used in the FROM directive but only BASE_SDK_VERSION is declared as an ARG. Either use the declared variable or add ARG BASE_IMAGE.

  3. applications/holocat/cpp/holocat_op.cpp, line 163-165 (link)

    logic: Unreachable code - return statement after throw will never execute.

19 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Copilot AI review requested due to automatic review settings December 18, 2025 16:21
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces HoloCat, a new application that integrates EtherCAT real-time industrial communication with NVIDIA's Holoscan SDK. It enables deterministic fieldbus communication for industrial automation applications using the commercial acontis EC-Master SDK.

Key Changes:

  • Complete EtherCAT master implementation with Holoscan operator architecture
  • Three operators: HolocatOp (main EtherCAT master), HcDataTxOp (data transmission), and HcDataRxOp (data reception)
  • Docker containerization with verification scripts and CMake build system

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
applications/holocat/metadata.json Application metadata with dependencies and configuration modes; category needs correction
applications/holocat/cpp/main.cpp Main entry point with CLI argument parsing; missing return statement
applications/holocat/cpp/holocat_op.{hpp,cpp} Core EtherCAT operator with state machine; unreachable code present
applications/holocat/cpp/holocat_app.{hpp,cpp} Application composition and config validation; format string inconsistency
applications/holocat/cpp/hc_data_tx_op.{hpp,cpp} Counter data generator operator; minor typo in comment
applications/holocat/cpp/hc_data_rx_op.{hpp,cpp} Data receiver operator; incorrect file header documentation
applications/holocat/cpp/CMakeLists.txt C++ build configuration with EC-Master SDK integration
applications/holocat/CMakeLists.txt Top-level build script; unreachable exit statement
applications/holocat/FindEcMaster.cmake CMake module for locating EC-Master SDK installation
applications/holocat/configs/holocat_config.yaml Runtime configuration; contains hardcoded developer-specific paths
applications/holocat/configs/eni2.xml EtherCAT Network Information configuration file
applications/holocat/scripts/verify_ecmaster.sh SDK verification utility; hardcoded path in example
applications/holocat/Dockerfile Container build definition; critical BASE_IMAGE variable issue
applications/holocat/README.md Documentation with setup and usage instructions; list numbering and hardcoded path issues
applications/CMakeLists.txt Adds holocat to build system

"aarch64"
],
"tags": [
"EtherCAT"
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The category "EtherCAT" is not in the approved category list. Based on the README description, this application provides "deterministic EtherCAT communication capabilities" for "Real-time Control" and appears to be focused on networking and industrial communication.

Please replace "EtherCAT" with an existing category from the approved category list. Here are some suitable alternatives:

  • For industrial real-time communication: Networking and Distributed Computing
  • For real-time control aspects: Robotics
  • For communication protocols: Interoperability

The most appropriate would be Networking and Distributed Computing or Interoperability given the EtherCAT protocol's focus on industrial networking.

Copilot generated this review using guidance from repository custom instructions.
holoscan::ExecutionContext& context) override;

private:
// coutner from 0 to maxcount for output on ECat bus
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: "coutner" should be "counter".

Suggested change
// coutner from 0 to maxcount for output on ECat bus
// counter from 0 to maxcount for output on ECat bus

Copilot uses AI. Check for mistakes.
HOLOSCAN_LOG_ERROR("Cannot initialize EtherCAT-Master: {} (0x{:x})",
ecatGetText(dwRes), dwRes);
throw std::runtime_error("Cannot initialize EtherCAT-Master: " + std::string(ecatGetText(dwRes)));
return;
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unreachable code: The return statement on line 165 will never be executed because line 164 throws an exception. Remove the return statement.

Suggested change
return;

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +9
adapter_name: "enxc84bd6d2788c"

# EtherCAT Network Information (ENI) file path
# Use environment variable HOLOCAT_ENI_FILE to override, or falls back to config dir
eni_file: "/home/hking/devel/holo/holohub/applications/holocat/configs/eni2.xml"
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded user-specific paths in configuration file. The adapter_name "enxc84bd6d2788c" and eni_file path "/home/hking/devel/holo/holohub/applications/holocat/configs/eni2.xml" contain developer-specific information that should be replaced with generic placeholders or relative paths. Consider using:

  • adapter_name: "eth0" (as shown in the README example)
  • eni_file: A relative path or environment variable-based path
Suggested change
adapter_name: "enxc84bd6d2788c"
# EtherCAT Network Information (ENI) file path
# Use environment variable HOLOCAT_ENI_FILE to override, or falls back to config dir
eni_file: "/home/hking/devel/holo/holohub/applications/holocat/configs/eni2.xml"
adapter_name: "eth0"
# EtherCAT Network Information (ENI) file path
# Use environment variable HOLOCAT_ENI_FILE to override, or falls back to config dir
eni_file: "eni2.xml"

Copilot uses AI. Check for mistakes.
### Prerequisites
```bash
# Set EC-Master SDK path
export ECMASTER_ROOT=/home/hking/devel/ethercat/ecm
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded user-specific path in documentation. The path "/home/hking/devel/ethercat/ecm" is developer-specific and should be replaced with a generic placeholder like "/path/to/ec-master" or "/opt/acontis/ecmaster".

Suggested change
export ECMASTER_ROOT=/home/hking/devel/ethercat/ecm
export ECMASTER_ROOT=/opt/acontis/ecmaster # Adjust to your EC-Master install path

Copilot uses AI. Check for mistakes.
sudo setcap 'cap_net_raw=ep' ./build/holocat/applications/holocat/holocat
```

3. **EC-Master SDK Not Found**
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List numbering is incorrect. The list jumps from "1. Permission Denied" to "3. EC-Master SDK Not Found", skipping item 2. Either add the missing item 2 or renumber item 3 as item 2.

Suggested change
3. **EC-Master SDK Not Found**
2. **EC-Master SDK Not Found**

Copilot uses AI. Check for mistakes.
print_status "ERROR" "ECMASTER_ROOT environment variable not set"
echo " Set it to your EC-Master installation path:"
echo " export ECMASTER_ROOT=/path/to/ecm"
echo " Example: export ECMASTER_ROOT=/home/hking/devel/ethercat/ecm"
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded user-specific path in example. Line 38 contains a developer-specific path "/home/hking/devel/ethercat/ecm" in the example that should use a generic placeholder path like "/path/to/ec-master" or "/opt/acontis/ecmaster".

Suggested change
echo " Example: export ECMASTER_ROOT=/home/hking/devel/ethercat/ecm"
echo " Example: export ECMASTER_ROOT=/opt/acontis/ecmaster"

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +29

# Exit with failure
exit(1)
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exit(1) command on line 29 is unreachable because message(FATAL_ERROR) on line 26 already terminates the CMake configuration process. Remove lines 28-29 as they serve no purpose.

Suggested change
# Exit with failure
exit(1)

Copilot uses AI. Check for mistakes.
std::shared_ptr<HolocatOp> holocat_op = make_operator<HolocatOp>("holocat_op", ecat_bus_periodic_cond);
holocat_op->set_config(config);
add_operator(holocat_op);
HOLOSCAN_LOG_INFO("HoloCat operator created with %dus periodic condition", config.cycle_time_us);
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent log formatting. Line 39 uses printf-style format string "%dus" while other log statements in the same function (lines 30, 31) use modern C++ format string style with "{}". Use the consistent format string style: HOLOSCAN_LOG_INFO("HoloCat operator created with {}us periodic condition", config.cycle_time_us);

Suggested change
HOLOSCAN_LOG_INFO("HoloCat operator created with %dus periodic condition", config.cycle_time_us);
HOLOSCAN_LOG_INFO("HoloCat operator created with {}us periodic condition", config.cycle_time_us);

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +32
usermod -aG sudo holocat && \
echo "holocat ALL=(ALL) NOPASSWD: /usr/sbin/setcap" >> /etc/sudoers

Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Dockerfile grants the holocat user passwordless sudo access to /usr/sbin/setcap, which allows that user (and any code running as it) to assign arbitrary Linux capabilities to any binary in the container. If an attacker gains code execution as holocat, they can use sudo setcap to escalate privileges and grant powerful capabilities (e.g., raw network, sys_admin) to other binaries, breaking the intended least-privilege isolation. Consider removing this sudoers entry and instead setting the minimal required capabilities at build time or via the container runtime, without allowing arbitrary setcap invocation from inside the container.

Suggested change
usermod -aG sudo holocat && \
echo "holocat ALL=(ALL) NOPASSWD: /usr/sbin/setcap" >> /etc/sudoers
usermod -aG sudo holocat

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (9)

  1. applications/CMakeLists.txt, line 152 (link)

    style: The holocat application should be placed in alphabetical order per the comment on line 16. It should be positioned between 'high_speed_endoscopy' and 'holochat'.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  2. applications/holocat/CMakeLists.txt, line 28-29 (link)

    logic: unreachable code after FATAL_ERROR - CMake stops processing after the fatal error message

  3. applications/holocat/cpp/hc_data_tx_op.hpp, line 53 (link)

    syntax: Typo: 'coutner' should be 'counter'

  4. applications/holocat/cpp/holocat_op.cpp, line 165 (link)

    syntax: unreachable code after throw statement

  5. applications/holocat/cpp/hc_data_rx_op.hpp, line 42 (link)

    style: Documentation inconsistency - comment states op_input is unused but this is a receiver operator, not a source operator

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  6. applications/holocat/Dockerfile, line 4 (link)

    logic: BASE_IMAGE variable is undefined. Change to BASE_SDK_VERSION or add ARG BASE_IMAGE declaration.

  7. applications/holocat/metadata.json, line 5-7 (link)

    style: missing author name field - only affiliation is specified. Should an author name be added to the metadata?

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  8. applications/holocat/cpp/holocat_app.cpp, line 42-43 (link)

    style: Condition name 'ethercat_cycle' is used for both EtherCAT bus and counter update conditions, but they have different periods (configurable vs 100ms). Consider using distinct names. Should these conditions have the same name when they serve different purposes with different timing?

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  9. applications/holocat/cpp/hc_data_rx_op.cpp, line 5-6 (link)

    syntax: Comment incorrectly describes HcDataTxOp instead of HcDataRxOp

19 files reviewed, 9 comments

Edit Code Review Agent Settings | Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants