Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
56 changes: 18 additions & 38 deletions common/rs-config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@

#include "rs-config.h"

#include <librealsense2/rs.h>
#include <rsutils/os/special-folder.h>
#include <nlohmann/json.hpp>

#include "model-views.h"

#include <rsutils/json.h>
#include <fstream>

#include "os.h"

using json = nlohmann::json;

using namespace rs2;

void config_file::set(const char* key, const char* value)
{
_values[key] = value;
_j[key] = value;
save();
}

Expand All @@ -29,30 +25,30 @@ void config_file::set_default(const char* key, const char* calculate)

void config_file::remove(const char* key)
{
_values.erase(key);
_j.erase(key);
save();
}

void config_file::reset()
{
_values.clear();
_j = nlohmann::json::object();
save();
}

std::string config_file::get(const char* key, const char* def) const
{
auto it = _values.find(key);
if (it != _values.end())
auto it = _j.find(key);
if (it != _j.end() && it->is_string())
{
return it->second;
return rsutils::json::string_ref( *it );
}
return get_default(key, def);
}

bool config_file::contains(const char* key) const
{
auto it = _values.find(key);
return it != _values.end();
auto it = _j.find(key);
return it != _j.end() && it->is_string();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why check for string? Don't we support other values?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because, at least in rs-config, and in this PR, I didn't want to change any existing functionality: tools will keep behaving the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My main goal was to make rs-config compatible with raw json -- before, it couldn't even load -- and able to keep non-string content intact.

Copy link
Contributor

Choose a reason for hiding this comment

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

So in the next PR this is about to change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I'm not touching it again without a good reason.

}

std::string config_file::get_default(const char* key, const char* def) const
Expand All @@ -70,16 +66,10 @@ config_value config_file::get(const char* key) const

void config_file::save(const char* filename)
{
json j;
for(auto kvp : _values)
{
j[kvp.first] = kvp.second;
}
std::string s = j.dump(2);
try
{
std::ofstream out(filename);
out << s;
out << _j.dump( 2 );
out.close();
}
catch (...)
Expand All @@ -90,28 +80,18 @@ void config_file::save(const char* filename)
config_file& config_file::instance()
{
static config_file inst( rsutils::os::get_special_folder( rsutils::os::special_folder::app_data )
+ "realsense-config.json" );
+ RS2_CONFIG_FILENAME );
return inst;
}

config_file::config_file(std::string filename)
: _filename(std::move(filename)), _values()
config_file::config_file( std::string const & filename )
: _filename( filename )
{
try
{

std::ifstream t(_filename);
if (!t.good()) return;
std::string str((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
if( ! str.empty() )
{
auto j = json::parse( str );
for( json::iterator it = j.begin(); it != j.end(); ++it )
{
_values[it.key()] = it.value().get< std::string >();
}
}
_j = json::parse( t );
}
catch(...)
{
Expand All @@ -125,15 +105,15 @@ void config_file::save()
}

config_file::config_file()
: _filename(""), _values()
: _j( nlohmann::json::object() )
{
}

config_file& config_file::operator=(const config_file& other)
{
if (this != &other)
{
_values = other._values;
_j = other._j;
_defaults = other._defaults;
save();
}
Expand All @@ -142,5 +122,5 @@ config_file& config_file::operator=(const config_file& other)

bool config_file::operator==(const config_file& other) const
{
return _values == other._values;
return _j == other._j;
}
7 changes: 4 additions & 3 deletions common/rs-config.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2017 Intel Corporation. All Rights Reserved.

#pragma once

#include <nlohmann/json.hpp>

#include <map>
#include <string>
#include <sstream>
Expand Down Expand Up @@ -40,7 +41,7 @@ namespace rs2
{
public:
config_file();
config_file(std::string filename);
config_file( std::string const & filename );

void set_default(const char* key, const char* calculate);

Expand Down Expand Up @@ -91,8 +92,8 @@ namespace rs2

void save();

std::map<std::string, std::string> _values;
std::map<std::string, std::string> _defaults;
std::string _filename;
nlohmann::json _j;
Copy link
Contributor

Choose a reason for hiding this comment

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

_j does not imply the member meaning, just the type. _config?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's the underlying json object. I can name it _json, but I don't know if that adds much...

Copy link
Contributor

Choose a reason for hiding this comment

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

The name should not change if we decide to switch from JSON to XML or other.
The meaning of this variable is to hold the configuration in memory.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

_data? _map? _key_value? Anything you pick is meaningless. :)
Let's be realistic. It's a file with an extension of .json.

};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Newline needed?

5 changes: 5 additions & 0 deletions include/librealsense2/h/rs_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ extern "C" {

/**
* \brief Creates RealSense context that is required for the rest of the API.
* Context settings are taken from the library configuration file's 'context' key.
* \param[in] api_version Users are expected to pass their version of \c RS2_API_VERSION to make sure they are running the correct librealsense version.
* \param[out] error If non-null, receives any error that occurs during this call, otherwise, errors are ignored.
* \return Context object
Expand All @@ -27,6 +28,10 @@ rs2_context* rs2_create_context(int api_version, rs2_error** error);
* \param[in] api_version Users are expected to pass their version of \c RS2_API_VERSION to make sure they are running the correct librealsense version.
* \param[in] json_settings Pointer to a string containing a JSON configuration to use, or null if none
* Possible <setting>:<default-value> :
* inherit: true - (bool) whether to inherit and override library configuration file values:
* the 'context' key in the file is taken as-is
* '<executable-name>/context' is merged, if it exists
* then the context-settings are merged
* dds: {} - (requires BUILD_WITH_DDS) false disables DDS; otherwise the DDS settings:
* domain: 0 - (int) the number of the DDS domain [0-232]
* participant: <exe name> - (string) the name of the participant
Expand Down
14 changes: 14 additions & 0 deletions include/librealsense2/rs.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ extern "C" {
#define RS2_API_VERSION_STR (VAR_ARG_STRING(RS2_API_MAJOR_VERSION.RS2_API_MINOR_VERSION.RS2_API_PATCH_VERSION))
#define RS2_API_FULL_VERSION_STR (VAR_ARG_STRING(RS2_API_MAJOR_VERSION.RS2_API_MINOR_VERSION.RS2_API_PATCH_VERSION.RS2_API_BUILD_VERSION))

/**
* The library keeps persistent global settings in a per-user configuration file. These settings can relate to tool
* behavior (e.g., realsense-viewer) or library functionality (context creation, etc.) where settings are accepted
* (e.g., rs2_create_context_ex).
*
* The filename is appended to the user's AppData folder on Windows (<AppData>/<filename>) and home directory as a
* hidden file on Linux (~/.<filename>).
*
* The content is a JSON file and by default contains an empty object so default values are used. JSON ordering may
* shift when written to by the various tools but the contents should stay the same. Any values that do not match the
* expected type may be ignored.
*/
#define RS2_CONFIG_FILENAME "realsense-config.json"

/**
* get the size of rs2_raw_data_buffer
* \param[in] buffer pointer to rs2_raw_data_buffer returned by rs2_send_and_receive_raw_data
Expand Down
48 changes: 42 additions & 6 deletions src/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,52 @@
#include <librealsense2/rs.h> // RS2_API_FULL_VERSION_STR
#include <src/librealsense-exception.h>

#include <rsutils/os/special-folder.h>
#include <rsutils/os/executable-name.h>
#include <rsutils/easylogging/easyloggingpp.h>
#include <rsutils/string/from.h>
#include <rsutils/json.h>
using json = nlohmann::json;

#include <fstream>


namespace librealsense {


static nlohmann::json load_settings( nlohmann::json const & context_settings )
{
// Allow ignoring of any other settings, global or not!
if( ! rsutils::json::get( context_settings, "inherit", true ) )
return context_settings;

nlohmann::json config;

// Load the realsense configuration file settings
std::ifstream f( rsutils::os::get_special_folder( rsutils::os::special_folder::app_data ) + RS2_CONFIG_FILENAME );
if( f.good() )
{
try
{
config = nlohmann::json::parse( f );
}
catch( std::exception const & e )
{
throw std::runtime_error( "failed to load configuration file: " + std::string( e.what() ) );
}
}

config = rsutils::json::load_settings( config, "context", "config-file" );

// Patch the given context settings into the configuration
rsutils::json::patch( config, context_settings, "context settings" );
return config;
}


namespace librealsense
{
context::context( json const & settings )
: _settings( settings )
, _device_mask( rsutils::json::get< unsigned >( settings, "device-mask", RS2_PRODUCT_LINE_ANY ) )
: _settings( load_settings( settings ) ) // global | application | local
, _device_mask( rsutils::json::get< unsigned >( _settings, "device-mask", RS2_PRODUCT_LINE_ANY ) )
{
static bool version_logged = false;
if( ! version_logged )
Expand All @@ -49,7 +84,7 @@ namespace librealsense


context::context( char const * json_settings )
: context( json_settings ? json::parse( json_settings ) : json() )
: context( json_settings ? json::parse( json_settings ) : json::object() )
{
}

Expand Down Expand Up @@ -141,4 +176,5 @@ namespace librealsense
}
}

}

} // namespace librealsense
6 changes: 2 additions & 4 deletions src/dds/rsdds-device-factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,8 @@ static std::mutex domain_context_by_id_mutex;
rsdds_device_factory::rsdds_device_factory( context & ctx, callback && cb )
: super( ctx )
{
nlohmann::json dds_settings = rsutils::json::get< nlohmann::json >( _context.get_settings(),
std::string( "dds", 3 ),
nlohmann::json::object() );
if( dds_settings.is_object() )
nlohmann::json const & dds_settings = rsutils::json::nested( _context.get_settings(), std::string( "dds", 3 ) );
if( dds_settings.is_object() && rsutils::json::get( dds_settings, std::string( "enabled", 7 ), true ) )
{
auto domain_id = rsutils::json::get< realdds::dds_domain_id >( dds_settings, std::string( "domain", 6 ), 0 );
std::string participant_name = rsutils::json::get< std::string >( dds_settings,
Expand Down
7 changes: 4 additions & 3 deletions third-party/realdds/doc/discovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ The `context` has been augmented to be able to see DDS devices. This is on by de

When a context is created, a JSON representation may be passed to it, e.g.: `{"dds": { "domain": 123, "participant": "librs" }}`. This allows various customizations:

| Field | Description |
|----------------------|----------------------------------------|
| dds | Set to `false` to turn off DDS in this context; otherwise a JSON object
| Field | Default | Description |
|----------------------|--------:|------------------------------|
| dds | `{}` | Set to `false` to turn off DDS in this context
| dds/`enabled` | `true` | If `false`, DDS is disabled

The `dds` is there by default (i.e., not `false`). The value may contain the following settings dealing with discovery:

Expand Down
7 changes: 5 additions & 2 deletions third-party/realdds/include/realdds/dds-participant.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ class dds_participant
dds_participant( const dds_participant & ) = delete;
~dds_participant();

// Creates the underlying DDS participant and sets the QoS
// If need to use callbacks set them before calling init, they may be called before init returns.
// Creates the underlying DDS participant and sets the QoS.
// If callbacks are needed, set them before calling init. Note they may be called before init returns!
//
// The domain ID may be -1: in this case the settings "domain" is queried and a default of 0 is used
//
void init( dds_domain_id, std::string const & participant_name, nlohmann::json const & settings );

bool is_valid() const { return ( nullptr != _participant ); }
Expand Down
8 changes: 8 additions & 0 deletions third-party/realdds/src/dds-participant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <fastdds/rtps/transport/UDPv4TransportDescriptor.h>

#include <rsutils/string/slice.h>
#include <rsutils/json.h>

#include <map>
#include <mutex>
Expand Down Expand Up @@ -194,6 +195,13 @@ void dds_participant::init( dds_domain_id domain_id, std::string const & partici
+ std::to_string( domain_id ) );
}

if( domain_id == -1 )
{
// Get it from settings and default to 0
if( ! rsutils::json::get_ex( settings, "domain", &domain_id ) )
domain_id = 0;
}

_domain_listener = std::make_shared< listener_impl >( *this );

// Initialize the timestr "start" time
Expand Down
Loading