Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Test Ethernet Configuration Python API. Fix bug in ip fields
  • Loading branch information
OhadMeir committed Aug 19, 2025
commit 549f5e07dd4864427f6db05aef915efbfbeadbad
2 changes: 1 addition & 1 deletion examples/eth-config/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ set_target_properties( ${PROJECT_NAME} PROPERTIES FOLDER "Examples" )

using_easyloggingpp( ${PROJECT_NAME} SHARED )

install( TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
install( TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
22 changes: 12 additions & 10 deletions examples/eth-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The example shows how to:
### Configuration Parameters
- **Link Speed**: Current Ethernet link speed in Mbps (read-only, 0 if no link established)
- **Link Priority**: Controls whether the device prefers USB or Ethernet connection
- **Link Timeout**: Controls when to fallback from prefered link type to the other (milliseconds)
- **IP Address**: Shows both configured and actual IP address values
- **Network Mask**: Shows both configured and actual subnet mask values
- **Gateway**: Shows both configured and actual gateway values
Expand All @@ -41,25 +42,26 @@ RealSense Ethernet Configuration Example

Found Ethernet-capable device:
Name: Intel RealSense D555
Serial: 123456789
FW Version: 5.15.0.2
Serial: 333422302656
FW Version: 7.56.19918.835

=== Current Ethernet Configuration ===
Link Speed: 1000 Mbps
Link Priority: usb-first
IP Address: 192.168.1.100 (actual: 192.168.1.101)
Link Priority: Dynamic Eth First
Link Timeout: 4000 milliseconds
IP Address: 192.168.11.55 (actual: 192.168.11.55)
Network Mask: 255.255.255.0 (actual: 255.255.255.0)
Gateway: 192.168.1.1 (actual: 192.168.1.1)
DHCP Enabled: Yes
Gateway: 192.168.11.1 (actual: 192.168.11.1)
DHCP Enabled: No
DHCP Timeout: 30 seconds
MTU: 9000 bytes
TX Delay: 0 microseconds

=== Demonstrating Configuration Changes ===

Demonstrating link priority change...
Setting link priority to Ethernet First
Link priority changed from usb-first to eth-first
Setting link priority to Eth First
Link priority changed from Dynamic Eth First to Eth First

Demonstrating DHCP timeout change...
Setting DHCP timeout to 60 seconds
Expand Down Expand Up @@ -92,9 +94,9 @@ Configuration restored to original values

### Main Functions
- `print_ethernet_config()`: Displays current configuration including link speed and configured vs actual IP values
- `demonstrate_config_changes()`: Shows how to modify non-critical settings safely
- `print_link_speed()`: Reads and displays current link speed using direct C API
- `demonstrate_config_changes()`: Shows how to modify selected settings safely

### Helper Functions
- `link_priority_to_string()`: Converts enum to readable string
- `format_ip_address()`: Formats IP addresses for display, handles invalid addresses
- `print_link_speed()`: Reads and displays current link speed
6 changes: 3 additions & 3 deletions src/rs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4737,7 +4737,7 @@ HANDLE_EXCEPTIONS_AND_RETURN( , device )
void rs2_set_ip_address( const rs2_device * device, const rs2_ip_address ip, rs2_error ** error ) BEGIN_API_CALL
{
auto config = get_eth_config( device );
config.actual.ip = ip;
config.configured.ip = ip;
set_eth_config( device, config );
}
HANDLE_EXCEPTIONS_AND_RETURN(, device )
Expand All @@ -4753,7 +4753,7 @@ HANDLE_EXCEPTIONS_AND_RETURN( , device )
void rs2_set_netmask( const rs2_device * device, const rs2_ip_address netmask, rs2_error ** error ) BEGIN_API_CALL
{
auto config = get_eth_config( device );
config.actual.netmask = netmask;
config.configured.netmask = netmask;
set_eth_config( device, config );
}
HANDLE_EXCEPTIONS_AND_RETURN( , device )
Expand All @@ -4769,7 +4769,7 @@ HANDLE_EXCEPTIONS_AND_RETURN( , device )
void rs2_set_gateway( const rs2_device * device, const rs2_ip_address gateway, rs2_error ** error ) BEGIN_API_CALL
{
auto config = get_eth_config( device );
config.actual.gateway = gateway;
config.configured.gateway = gateway;
set_eth_config( device, config );
}
HANDLE_EXCEPTIONS_AND_RETURN( , device )
Expand Down
2 changes: 2 additions & 0 deletions third-party/rsutils/py/pyrsutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ PYBIND11_MODULE(NAME, m) {
.def( "empty", &ip_address::empty )
.def( "clear", &ip_address::clear )
.def( "__str__", &ip_address::to_string )
.def( "__eq__", &ip_address::operator== )
.def( "__ne__", &ip_address::operator!= )
.def( "get_components", []( const ip_address & self, uint8_t & b0, uint8_t & b1, uint8_t & b2, uint8_t & b3 ) { self.get_components( b0, b1, b2, b3 ); }, "Get IP address components" )
.def( "get_components", []( const ip_address & self, uint8_t b[4] ) { self.get_components( b ); }, "Get IP address components" );

Expand Down
6 changes: 6 additions & 0 deletions third-party/rsutils/src/eth-config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ void eth_config::validate() const
if( header.version != 3 && header.version != 4 )
throw std::invalid_argument( rsutils::string::from() << "Unrecognized Eth config table version " << header.version );

if( ! configured.ip.is_valid() )
throw std::invalid_argument( rsutils::string::from() << "Invalid configured IP address " << configured.ip );
if( ! configured.netmask.is_valid() )
throw std::invalid_argument( rsutils::string::from() << "Invalid configured network mask " << configured.netmask );
// Allowing gateway to be 0.0.0.0 (unset). Camera will only communicate in local network.

if( dhcp.timeout < 0 )
throw std::invalid_argument( rsutils::string::from() << "DHCP timeout cannot be negative. Current " << dhcp.timeout );
Comment thread
OhadMeir marked this conversation as resolved.
Outdated

Expand Down
35 changes: 31 additions & 4 deletions unit-tests/live/config/test-eth-config.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,25 @@ def set_eth_config( config ):
test.unreachable()
new_config.header.version = orig_config.header.version

new_config.dhcp.timeout = -1
new_config.configured.ip = rsutils.ip_address( 0, 0 ,0 ,0 )
try:
set_eth_config( new_config )
except ValueError as e:
test.check_exception( e, ValueError, "DHCP timeout cannot be negative. Current -1" )
test.check_exception( e, ValueError, "Invalid configured IP address 0.0.0.0" )
else:
test.unreachable()
new_config.dhcp.timeout = orig_config.dhcp.timeout
new_config.configured.ip = orig_config.configured.ip

new_config.configured.netmask = rsutils.ip_address( 0, 0 ,0 ,0 )
try:
set_eth_config( new_config )
except ValueError as e:
test.check_exception( e, ValueError, "Invalid configured network mask 0.0.0.0" )
else:
test.unreachable()
new_config.configured.netmask = orig_config.configured.netmask

# Don't set valid domain_id, it might cause DDS devices to loose connection.
# Don't set valid domain_id, it might cause DDS devices to loose connection (in case of reset/power loss).
new_config.dds.domain_id = -1
try:
set_eth_config( new_config )
Expand All @@ -139,6 +148,24 @@ def set_eth_config( config ):
test.unreachable()
new_config.dds.domain_id = orig_config.dds.domain_id

with test.closure("Test python wrapper functionality"):
eth_device = rs.eth_config_device( dev )
orig_link_timeout = eth_device.get_link_timeout()
eth_device.set_link_timeout( orig_link_timeout * 2 )
updated_link_timeout = eth_device.get_link_timeout()
test.check( updated_link_timeout == orig_link_timeout * 2 )

orig_ip, orig_actual_ip = eth_device.get_ip_address()
eth_device.set_ip_address( rs.ip_address( 127, 0, 0, 1 ) )
new_ip, new_actual_ip = eth_device.get_ip_address()
test.check( new_ip == rs.ip_address( 127, 0, 0, 1 ) )

orig_link_priority = eth_device.get_link_priority()
priority_to_set = rs.link_priority.usb_first if orig_link_priority != rs.link_priority.usb_first else rs.link_priority.eth_first
eth_device.set_link_priority( priority_to_set )
new_link_priority = eth_device.get_link_priority()
test.check( new_link_priority == priority_to_set )

with test.closure("Restore configuration"):
set_eth_config( orig_config )

Expand Down
15 changes: 11 additions & 4 deletions wrappers/python/pyrs_eth_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ void init_eth_config(py::module &m) {

// Found also in pyrsutils. Here to avoid dependency (need to import pyrsutils whenever importing pyrealsense2)
// Using pyrsutils ip_address, not rs2_ip_address, because python must work on objects, not native type array.
//
// TODO - try importing both pyrsutils and pyrealsense2 and create an ip_address object. Verify it works
using rsutils::type::ip_address;
py::class_< ip_address >( m, "ip_address" )
.def( py::init<>() )
Expand All @@ -21,13 +19,20 @@ void init_eth_config(py::module &m) {
.def( "empty", &ip_address::empty )
.def( "clear", &ip_address::clear )
.def( "__str__", &ip_address::to_string )
.def( "__eq__", &ip_address::operator== )
.def( "__ne__", &ip_address::operator!= )
.def( "get_components", []( const ip_address & self, uint8_t & b0, uint8_t & b1, uint8_t & b2, uint8_t & b3 ) { self.get_components( b0, b1, b2, b3 ); }, "Get IP address components" )
.def( "get_components", []( const ip_address & self, uint8_t b[4] ) { self.get_components( b ); }, "Get IP address components" );

/** rs_eth_config.hpp **/

// Bind the enum
BIND_ENUM( m, rs2_eth_link_priority, RS2_LINK_PRIORITY_COUNT, "Ethernet link priority options" );
py::enum_< rs2_eth_link_priority >( m, "link_priority" )
.value( "usb_only", RS2_LINK_PRIORITY_USB_ONLY )
.value( "eth_only", RS2_LINK_PRIORITY_ETH_ONLY )
.value( "eth_first", RS2_LINK_PRIORITY_ETH_FIRST )
.value( "usb_first", RS2_LINK_PRIORITY_USB_FIRST )
.value( "dynamic_eth_first", RS2_LINK_PRIORITY_DYNAMIC_ETH_FIRST )
.value( "dynamic_usb_first", RS2_LINK_PRIORITY_DYNAMIC_USB_FIRST );

// Bind the eth_config_device class
py::class_< rs2::eth_config_device, rs2::device > eth_config_device( m, "eth_config_device",
Expand All @@ -37,6 +42,8 @@ void init_eth_config(py::module &m) {
.def( "get_link_speed", &rs2::eth_config_device::get_link_speed, "Get Ethernet link speed, 0 if not linked" )
.def( "get_link_priority", &rs2::eth_config_device::get_link_priority, "Get current link priority setting" )
.def( "set_link_priority", &rs2::eth_config_device::set_link_priority, "Set link priority", "priority"_a )
.def( "get_link_timeout", &rs2::eth_config_device::get_link_timeout, "Get current link timeout in milliseconds" )
.def( "set_link_timeout", &rs2::eth_config_device::set_link_timeout, "Set link timeout in milliseconds", "timeout"_a )
.def( "get_ip_address", []( const rs2::eth_config_device & self )
{
rs2_ip_address configured_ip, actual_ip;
Expand Down