FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
api.cpp File Reference

Implementation of the C-style FFI for the libfers core library. More...

#include <algorithm>
#include <cmath>
#include <core/logging.h>
#include <core/parameters.h>
#include <core/sim_id.h>
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <format>
#include <functional>
#include <iterator>
#include <libfers/api.h>
#include <limits>
#include <math/path.h>
#include <math/rotation_path.h>
#include <mutex>
#include <nlohmann/json.hpp>
#include <optional>
#include <span>
#include <string>
#include <utility>
#include <vector>
#include "antenna/antenna_factory.h"
#include "core/fers_context.h"
#include "core/memory_projection.h"
#include "core/sim_threading.h"
#include "core/thread_pool.h"
#include "fers_version.h"
#include "serial/json_serializer.h"
#include "serial/kml_generator.h"
#include "serial/rotation_angle_utils.h"
#include "serial/rotation_warning_utils.h"
#include "serial/xml_parser.h"
#include "serial/xml_serializer.h"
#include "signal/radar_signal.h"
#include "simulation/channel_model.h"
+ Include dependency graph for api.cpp:

Go to the source code of this file.

Classes

struct  fers_context
 

Functions

static void handle_api_exception (const std::exception &e, const std::string &function_name)
 Centralized exception handler for the C-API boundary.
 
static void begin_warning_capture () noexcept
 
static void complete_warning_capture ()
 
static void discard_warning_capture () noexcept
 
fers_context_tfers_context_create ()
 Creates a new FERS simulation context.
 
void fers_context_destroy (fers_context_t *context)
 Destroys a FERS simulation context and releases all associated memory.
 
static logging::Level map_api_log_level (fers_log_level_t level)
 
static fers_log_level_t map_internal_log_level (logging::Level level)
 
int fers_configure_logging (fers_log_level_t level, const char *log_file_path)
 Configures the internal logger.
 
const charfers_get_version (void)
 Returns the library version string.
 
fers_log_level_t fers_get_log_level ()
 Returns the current internal logger level.
 
void fers_set_log_callback (fers_log_callback_t callback, void *user_data)
 Registers a callback for formatted log lines.
 
void fers_log (fers_log_level_t level, const char *message)
 Submits a log message to the library's unified logging system.
 
int fers_set_thread_count (unsigned num_threads)
 Sets the number of worker threads for the simulation.
 
int fers_set_output_directory (fers_context_t *context, const char *out_dir)
 Sets the output directory for simulation results.
 
int fers_use_hdf5_output (fers_context_t *context)
 Resets the context output mode to the default HDF5 output.
 
int fers_enable_vita49_udp_output (fers_context_t *context, const char *host, const std::uint16_t port)
 
int fers_set_vita49_fullscale (fers_context_t *context, const double fullscale)
 Sets the fixed ADC full-scale value used by the FERS VITA 49.2 int16 IQ profile.
 
int fers_set_vita49_epoch_unix_nanoseconds (fers_context_t *context, const std::uint64_t epoch_unix_nanoseconds)
 
int fers_set_vita49_max_udp_payload (fers_context_t *context, const std::uint16_t max_udp_payload)
 
int fers_set_vita49_queue_depth (fers_context_t *context, const std::uint32_t queue_depth)
 
int fers_set_vita49_packet_trace_enabled (fers_context_t *context, const int enabled)
 Enables or disables FERS VITA 49.2 packet trace telemetry.
 
int fers_load_scenario_from_xml_file (fers_context_t *context, const char *xml_filepath, const int validate)
 Loads a scenario into the context from a FERS XML file.
 
int fers_load_scenario_from_xml_string (fers_context_t *context, const char *xml_content, const int validate)
 Loads a scenario into the context from a FERS XML string.
 
charfers_get_scenario_as_json (fers_context_t *context)
 Serializes the current simulation scenario into a JSON string.
 
charfers_get_scenario_as_xml (fers_context_t *context)
 Serializes the current simulation scenario into a FERS XML string.
 
charfers_get_last_output_metadata_json (fers_context_t *context)
 Returns JSON metadata for the most recent simulation output files.
 
charfers_get_memory_projection_json (fers_context_t *context)
 Returns a JSON projection of simulation startup memory and HDF5 payload size.
 
int fers_update_platform_from_json (fers_context_t *context, uint64_t id, const char *json)
 Updates a single platform's paths and name from JSON without full context recreation.
 
int fers_update_parameters_from_json (fers_context_t *context, const char *json)
 Updates the global simulation parameters from JSON without full context recreation.
 
int fers_update_antenna_from_json (fers_context_t *context, const char *json)
 Updates a single antenna from JSON without full context recreation.
 
int fers_update_waveform_from_json (fers_context_t *context, const char *json)
 Updates a single waveform from JSON without full context recreation.
 
int fers_update_transmitter_from_json (fers_context_t *context, uint64_t id, const char *json)
 Updates a single transmitter from JSON without full context recreation.
 
int fers_update_receiver_from_json (fers_context_t *context, uint64_t id, const char *json)
 Updates a single receiver from JSON without full context recreation.
 
int fers_update_target_from_json (fers_context_t *context, uint64_t id, const char *json)
 Updates a single target from JSON without full context recreation.
 
int fers_update_monostatic_from_json (fers_context_t *context, const char *json)
 Updates a monostatic radar from JSON without full context recreation.
 
int fers_update_timing_from_json (fers_context_t *context, uint64_t id, const char *json)
 Updates a single timing source from JSON without full context recreation.
 
int fers_update_scenario_from_json (fers_context_t *context, const char *scenario_json)
 Updates the simulation scenario from a JSON string.
 
charfers_get_last_error_message ()
 Retrieves the last error message that occurred on the current thread.
 
charfers_get_last_warning_messages_json ()
 Returns the last deduplicated rotation-unit warning list for the calling thread as JSON.
 
void fers_free_string (char *str)
 Frees a string that was allocated and returned by the libfers API.
 
int fers_run_simulation (fers_context_t *context, fers_progress_callback_t callback, void *user_data)
 Runs the simulation defined in the provided context.
 
int fers_run_simulation_ex (fers_context_t *context, fers_progress_callback_t progress_callback, void *progress_user_data, fers_cancel_callback_t cancel_callback, void *cancel_user_data, fers_vita49_telemetry_callback_t vita49_telemetry_callback, void *vita49_telemetry_user_data)
 Runs the simulation with optional progress, cancellation, and VITA telemetry callbacks.
 
int fers_generate_kml (const fers_context_t *context, const char *output_kml_filepath)
 Generates a KML file for visualizing the scenario in the context.
 
math::Path::InterpType to_cpp_interp_type (const fers_interp_type_t type)
 
math::RotationPath::InterpType to_cpp_rot_interp_type (const fers_interp_type_t type)
 
fers_interpolated_path_tfers_get_interpolated_motion_path (const fers_motion_waypoint_t *waypoints, const size_t waypoint_count, const fers_interp_type_t interp_type, const size_t num_points)
 Calculates an interpolated motion path from a set of waypoints.
 
void fers_free_interpolated_motion_path (fers_interpolated_path_t *path)
 Frees the memory allocated for an interpolated motion path.
 
fers_interpolated_rotation_path_tfers_get_interpolated_rotation_path (const fers_rotation_waypoint_t *waypoints, const size_t waypoint_count, const fers_interp_type_t interp_type, const fers_angle_unit_t angle_unit, const size_t num_points)
 Calculates an interpolated rotation path from a set of waypoints.
 
void fers_free_interpolated_rotation_path (fers_interpolated_rotation_path_t *path)
 Frees the memory allocated for an interpolated rotation path.
 
fers_antenna_pattern_data_tfers_get_antenna_pattern (const fers_context_t *context, const uint64_t antenna_id, const size_t az_samples, const size_t el_samples, const double frequency_hz)
 Samples the gain pattern of a specified antenna and provides the data.
 
void fers_free_antenna_pattern_data (fers_antenna_pattern_data_t *data)
 Frees the memory allocated for an antenna pattern data structure.
 
fers_visual_link_list_tfers_calculate_preview_links (const fers_context_t *context, const double time)
 Calculates visual links for a specific simulation time.
 
void fers_free_preview_links (fers_visual_link_list_t *list)
 Frees the memory allocated for a preview link list.
 

Variables

thread_local std::string last_error_message
 
thread_local std::vector< std::stringlast_warning_messages
 

Detailed Description

Implementation of the C-style FFI for the libfers core library.

This file provides the C implementations for the functions declared in api.h. It acts as the bridge between the C ABI and the C++ core, handling object creation/destruction, exception catching, error reporting, and type casting.

Definition in file api.cpp.

Function Documentation

◆ begin_warning_capture()

static void begin_warning_capture ( )
staticnoexcept

Definition at line 78 of file api.cpp.

79{
82}
thread_local std::vector< std::string > last_warning_messages
Definition api.cpp:61
void clear_captured_warnings() noexcept
Clears the thread-local captured rotation warnings.

References serial::rotation_warning_utils::clear_captured_warnings(), and last_warning_messages.

Referenced by fers_load_scenario_from_xml_file(), fers_load_scenario_from_xml_string(), fers_update_parameters_from_json(), fers_update_platform_from_json(), and fers_update_scenario_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ complete_warning_capture()

static void complete_warning_capture ( )
static

Definition at line 84 of file api.cpp.

85{
87}
std::vector< std::string > take_captured_warnings()
Returns and clears the thread-local captured rotation warnings.

References last_warning_messages, and serial::rotation_warning_utils::take_captured_warnings().

Referenced by fers_load_scenario_from_xml_file(), fers_load_scenario_from_xml_string(), fers_update_parameters_from_json(), fers_update_platform_from_json(), and fers_update_scenario_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ discard_warning_capture()

static void discard_warning_capture ( )
staticnoexcept

Definition at line 89 of file api.cpp.

References serial::rotation_warning_utils::clear_captured_warnings(), and last_warning_messages.

Referenced by fers_context_create(), fers_load_scenario_from_xml_file(), fers_load_scenario_from_xml_string(), fers_update_parameters_from_json(), fers_update_platform_from_json(), and fers_update_scenario_from_json().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fers_calculate_preview_links()

fers_visual_link_list_t * fers_calculate_preview_links ( const fers_context_t context,
double  time 
)

Calculates visual links for a specific simulation time.

Parameters
contextThe simulation context.
timeThe simulation time in seconds.
Returns
A pointer to a link list. Caller must free with fers_free_preview_links.

Definition at line 1595 of file api.cpp.

1596{
1597 last_error_message.clear();
1598 if (context == nullptr)
1599 {
1600 last_error_message = "Invalid context passed to fers_calculate_preview_links";
1602 return nullptr;
1603 }
1604
1605 try
1606 {
1607 const auto* ctx = context;
1608 // Call the core physics logic in channel_model.cpp
1609 const auto cpp_links = simulation::calculatePreviewLinks(*ctx->getWorld(), time);
1610
1611 // Convert C++ vector to C-API struct
1612 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Public C API returns owned preview-link lists.
1613 auto* result = new fers_visual_link_list_t();
1614 result->count = cpp_links.size();
1615
1616 if (!cpp_links.empty())
1617 {
1618 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Public C API frees this array with the parent list.
1619 result->links = new fers_visual_link_t[result->count];
1620 for (size_t i = 0; i < result->count; ++i)
1621 {
1622 const auto& src = cpp_links[i];
1623 auto& dst = result->links[i];
1624
1625 // Map enums
1626 switch (src.type)
1627 {
1630 break;
1633 break;
1636 break;
1639 break;
1640 }
1641
1643
1645
1646 dst.source_id = static_cast<uint64_t>(src.source_id);
1647 dst.dest_id = static_cast<uint64_t>(src.dest_id);
1648 dst.origin_id = static_cast<uint64_t>(src.origin_id);
1649 dst.rcs = src.rcs;
1650 dst.actual_power_dbm = src.actual_power_dbm;
1651 dst.display_value = src.display_value;
1652 }
1653 }
1654 else
1655 {
1656 result->links = nullptr;
1657 }
1658 return result;
1659 }
1660 catch (const std::exception& e)
1661 {
1662 handle_api_exception(e, "fers_calculate_preview_links");
1663 return nullptr;
1664 }
1665}
static void handle_api_exception(const std::exception &e, const std::string &function_name)
Centralized exception handler for the C-API boundary.
Definition api.cpp:72
thread_local std::string last_error_message
Definition api.cpp:60
@ FERS_LINK_BISTATIC_TX_TGT
Definition api.h:743
@ FERS_LINK_MONOSTATIC
Definition api.h:742
@ FERS_LINK_BISTATIC_TGT_RX
Definition api.h:744
@ FERS_LINK_DIRECT_TX_RX
Definition api.h:745
@ FERS_LINK_WEAK
Definition api.h:734
@ FERS_LINK_STRONG
Definition api.h:733
#define LOG(level,...)
Definition logging.h:19
@ ERROR
Error level for error events.
@ DirectTxRx
Interference path.
@ Monostatic
Combined Tx/Rx path.
@ BistaticTgtRx
Scattered path.
@ BistaticTxTgt
Illuminator path.
std::vector< PreviewLink > calculatePreviewLinks(const core::World &world, const RealType time)
Calculates all visual links for the current world state at a specific time.
math::Vec3 max

References simulation::BistaticTgtRx, simulation::BistaticTxTgt, simulation::calculatePreviewLinks(), simulation::DirectTxRx, logging::ERROR, FERS_LINK_BISTATIC_TGT_RX, FERS_LINK_BISTATIC_TX_TGT, FERS_LINK_DIRECT_TX_RX, FERS_LINK_MONOSTATIC, FERS_LINK_STRONG, FERS_LINK_WEAK, handle_api_exception(), last_error_message, LOG, simulation::Monostatic, simulation::Strong, and fers_visual_link_t::type.

+ Here is the call graph for this function:

◆ fers_configure_logging()

int fers_configure_logging ( fers_log_level_t  level,
const char log_file_path 
)

Configures the internal logger.

Parameters
levelThe minimum severity level to log.
log_file_pathOptional path to a log file. Pass NULL to disable file logging.
Returns
0 on success, non-zero on error.

Definition at line 353 of file api.cpp.

354{
355 last_error_message.clear();
356 try
357 {
359 if ((log_file_path != nullptr) && ((*log_file_path) != 0))
360 {
362 if (!result)
363 {
364 last_error_message = result.error();
365 return 1;
366 }
367 }
368 return 0;
369 }
370 catch (const std::exception& e)
371 {
372 handle_api_exception(e, "fers_configure_logging");
373 return 1;
374 }
375}
static logging::Level map_api_log_level(fers_log_level_t level)
Definition api.cpp:129
std::expected< void, std::string > logToFile(const std::string &filePath) noexcept
Sets the log file path to log messages to a file.
Definition logging.cpp:90
void setLevel(Level level) noexcept
Sets the logging level.
Definition logging.cpp:25
Logger logger
Externally available logger object.
Definition logging.cpp:23

References handle_api_exception(), last_error_message, logging::logger, logging::Logger::logToFile(), map_api_log_level(), and logging::Logger::setLevel().

+ Here is the call graph for this function:

◆ fers_context_create()

fers_context_t * fers_context_create ( )

Creates a new FERS simulation context.

Allocates and initializes a new, empty simulation context in memory. This context serves as the container for a scenario loaded via one of the fers_load_... or fers_update_... functions.

Note
In a C API, RAII is not available. The caller is responsible for destroying the returned context using fers_context_destroy() to prevent resource leaks.
Returns
A non-null opaque pointer (handle) to the simulation context on success. Returns NULL on failure (e.g., out of memory).

Definition at line 97 of file api.cpp.

98{
99 last_error_message.clear();
101 try
102 {
103 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Public C API returns an owned handle.
104 return new fers_context_t();
105 }
106 catch (const std::bad_alloc& e)
107 {
108 handle_api_exception(e, "fers_context_create");
109 return nullptr;
110 }
111 catch (const std::exception& e)
112 {
113 handle_api_exception(e, "fers_context_create");
114 return nullptr;
115 }
116}
static void discard_warning_capture() noexcept
Definition api.cpp:89
struct fers_context fers_context_t
Definition api.h:26

References discard_warning_capture(), handle_api_exception(), and last_error_message.

+ Here is the call graph for this function:

◆ fers_context_destroy()

void fers_context_destroy ( fers_context_t context)

Destroys a FERS simulation context and releases all associated memory.

This function must be called for every context created by fers_context_create() to ensure proper cleanup of the underlying C++ objects. Accessing the context handle after calling this function results in undefined behavior.

Parameters
contextA valid pointer to a fers_context_t handle. If context is NULL, the function performs no action for safety and does not set an error.

Definition at line 118 of file api.cpp.

119{
120 if (context == nullptr)
121 {
122 return;
123 }
124 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Frees handles allocated by `fers_context_create`.
125 delete context;
126}

◆ fers_enable_vita49_udp_output()

int fers_enable_vita49_udp_output ( fers_context_t context,
const char host,
const std::uint16_t  port 
)

Definition at line 464 of file api.cpp.

465{
466 last_error_message.clear();
467 if (context == nullptr)
468 {
469 set_api_error("Invalid arguments: context is NULL.");
470 return -1;
471 }
472 if (host == nullptr)
473 {
474 set_api_error("Invalid VITA49 endpoint: host is NULL.");
475 return -1;
476 }
477 if (*host == '\0')
478 {
479 set_api_error("Invalid VITA49 endpoint: host must be non-empty.");
480 return 1;
481 }
482 if (port == 0)
483 {
484 set_api_error("Invalid VITA49 endpoint: port must be in the range 1..65535.");
485 return 1;
486 }
487
488 auto* ctx = context;
489 try
490 {
491 core::OutputConfig config = ctx->getOutputConfig();
493 config.vita49.host = host;
494 config.vita49.port = port;
495 ctx->setOutputConfig(std::move(config));
496 return 0;
497 }
498 catch (const std::exception& e)
499 {
500 handle_api_exception(e, "fers_enable_vita49_udp_output");
501 return 1;
502 }
503}

References handle_api_exception(), core::Vita49OutputConfig::host, last_error_message, core::OutputConfig::mode, core::Vita49OutputConfig::port, core::OutputConfig::vita49, and core::Vita49Udp.

+ Here is the call graph for this function:

◆ fers_free_antenna_pattern_data()

void fers_free_antenna_pattern_data ( fers_antenna_pattern_data_t data)

Frees the memory allocated for an antenna pattern data structure.

Parameters
dataA pointer to the fers_antenna_pattern_data_t struct to free.

Definition at line 1582 of file api.cpp.

1583{
1584 if (data != nullptr)
1585 {
1586 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Frees arrays owned by C API pattern structs.
1587 delete[] data->gains;
1588 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Frees structs allocated by `fers_get_antenna_pattern`.
1589 delete data;
1590 }
1591}

References fers_antenna_pattern_data_t::gains.

◆ fers_free_interpolated_motion_path()

void fers_free_interpolated_motion_path ( fers_interpolated_path_t path)

Frees the memory allocated for an interpolated motion path.

Parameters
pathA pointer to the fers_interpolated_path_t struct to free.

Definition at line 1379 of file api.cpp.

1380{
1381 if (path != nullptr)
1382 {
1383 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Frees arrays owned by C API path structs.
1384 delete[] path->points;
1385 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Frees structs allocated by
1386 // `fers_get_interpolated_motion_path`.
1387 delete path;
1388 }
1389}
fers_interpolated_point_t * points
Heap-allocated interpolated motion points.
Definition api.h:664

References fers_interpolated_path_t::points.

◆ fers_free_interpolated_rotation_path()

void fers_free_interpolated_rotation_path ( fers_interpolated_rotation_path_t path)

Frees the memory allocated for an interpolated rotation path.

Parameters
pathA pointer to the fers_interpolated_rotation_path_t struct to free.

Definition at line 1480 of file api.cpp.

1481{
1482 if (path != nullptr)
1483 {
1484 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Frees arrays owned by C API path structs.
1485 delete[] path->points;
1486 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Frees structs allocated by
1487 // `fers_get_interpolated_rotation_path`.
1488 delete path;
1489 }
1490}
fers_interpolated_rotation_point_t * points
Heap-allocated interpolated rotation points.
Definition api.h:674

References fers_interpolated_rotation_path_t::points.

◆ fers_free_preview_links()

void fers_free_preview_links ( fers_visual_link_list_t list)

Frees the memory allocated for a preview link list.

Parameters
listThe list to free.

Definition at line 1667 of file api.cpp.

1668{
1669 if (list != nullptr)
1670 {
1671 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Frees arrays owned by C API preview-link lists.
1672 delete[] list->links;
1673 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Frees structs allocated by `fers_calculate_preview_links`.
1674 delete list;
1675 }
1676}

References fers_visual_link_list_t::links.

◆ fers_free_string()

void fers_free_string ( char str)

Frees a string that was allocated and returned by the libfers API.

This function must be used to release memory for any string returned by functions like fers_get_scenario_as_json or fers_get_last_error_message. It exists to ensure that the memory deallocation mechanism (free) matches the allocation mechanism (strdup/malloc) used within the C++ library, preventing potential crashes from mismatched allocators across language boundaries.

Parameters
strA pointer to the string to be freed. If str is NULL, no action is taken.

Definition at line 1109 of file api.cpp.

1110{
1111 if (str != nullptr)
1112 {
1113 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Public C API frees strings returned by this library.
1114 free(str);
1115 }
1116}

◆ fers_generate_kml()

int fers_generate_kml ( const fers_context_t context,
const char output_kml_filepath 
)

Generates a KML file for visualizing the scenario in the context.

This utility exists to provide a simple, out-of-the-box method for users to validate and visualize the geographic layout and motion paths of their scenarios in common external tools like Google Earth.

Parameters
contextA valid fers_context_t handle containing a loaded scenario.
output_kml_filepathA null-terminated UTF-8 string for the output KML file path.
Returns
0 on success, a non-zero error code on failure. Use fers_get_last_error_message() to retrieve KML generation details.

Definition at line 1241 of file api.cpp.

1242{
1243 last_error_message.clear();
1244 if ((context == nullptr) || (output_kml_filepath == nullptr))
1245 {
1246 last_error_message = "Invalid arguments: context or output_kml_filepath is NULL.";
1248 return -1;
1249 }
1250
1251 const auto* ctx = context;
1252
1253 try
1254 {
1256 if (result)
1257 {
1258 return 0; // Success
1259 }
1260
1261 last_error_message = result.error();
1263 return 2; // Generation failed
1264 }
1265 catch (const std::exception& e)
1266 {
1267 handle_api_exception(e, "fers_generate_kml");
1268 return 1; // Exception thrown
1269 }
1270}
static std::expected< void, std::string > generateKml(const core::World &world, const std::string &outputKmlPath)
Generates a KML file from a pre-built simulation world.

References logging::ERROR, serial::KmlGenerator::generateKml(), handle_api_exception(), last_error_message, and LOG.

+ Here is the call graph for this function:

◆ fers_get_antenna_pattern()

fers_antenna_pattern_data_t * fers_get_antenna_pattern ( const fers_context_t context,
uint64_t  antenna_id,
size_t  az_samples,
size_t  el_samples,
double  frequency_hz 
)

Samples the gain pattern of a specified antenna and provides the data.

This function calculates the antenna's far-field gain at a specified resolution over the full sphere of directions (azimuth and elevation). The resulting gain values are linear (not in dB) and normalized relative to the pattern's peak gain. This is a stateless utility useful for UI previews and analysis.

Parameters
contextA valid fers_context_t handle containing a loaded scenario with the antenna.
antenna_idThe unique ID of the antenna asset to sample.
az_samplesThe desired number of sample points along the azimuth axis. Must be at least 2 to span the full azimuth range.
el_samplesThe desired number of sample points along the elevation axis. Must be at least 2 to span the full elevation range.
frequency_hzThe frequency in Hz to use for gain calculation (affects aperture antennas).
Returns
A pointer to a fers_antenna_pattern_data_t struct containing the results. Returns NULL on failure (e.g., antenna not found). The caller owns the returned struct and must free it with fers_free_antenna_pattern_data.

Definition at line 1494 of file api.cpp.

1497{
1498 last_error_message.clear();
1499 if ((context == nullptr) || az_samples < 2 || el_samples < 2)
1500 {
1501 last_error_message = "Invalid arguments: context must be non-null and sample counts must be >= 2.";
1503 return nullptr;
1504 }
1505
1506 try
1507 {
1508 const auto* ctx = context;
1509 antenna::Antenna const* ant = ctx->getWorld()->findAntenna(static_cast<SimId>(antenna_id));
1510
1511 if (ant == nullptr)
1512 {
1513 last_error_message = "Antenna ID '" + std::to_string(antenna_id) + "' not found in the world.";
1515 return nullptr;
1516 }
1517
1518 // TODO: Currently only using the first-found waveform. This is incorrect but also difficult to represent
1519 // correctly in scenarios with multiple waveforms as the gain for squarehorn and parabolic antennas
1520 // depends on the wavelength. Hence a decision needs to be made about whether to return multiple patterns
1521 // per waveform or have the user specify a representative wavelength in the UI per antenna.
1522 // Calculate wavelength from the provided frequency.
1523 // Default to 1GHz (0.3m) if frequency is invalid/zero, though the UI should prevent this
1524 // for antennas that strictly require it (Horn/Parabolic).
1525 RealType wavelength = 0.3;
1526 if (frequency_hz > 0.0)
1527 {
1529 }
1530
1531 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Public C API returns owned antenna pattern data.
1532 auto* data = new fers_antenna_pattern_data_t();
1533 data->az_count = az_samples;
1534 data->el_count = el_samples;
1535 const size_t total_samples = az_samples * el_samples;
1536 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Public C API frees this array with the parent data.
1537 data->gains = new double[total_samples];
1538
1539 // The reference angle (boresight) is implicitly the local X-axis in the FERS engine.
1540 // We pass a zero rotation to get the gain relative to this boresight.
1541 const math::SVec3 ref_angle(1.0, 0.0, 0.0);
1542 double max_gain = 0.0;
1543
1544 const auto az_denominator = static_cast<RealType>(az_samples - 1);
1545 const auto el_denominator = static_cast<RealType>(el_samples - 1);
1546
1547 for (size_t i = 0; i < el_samples; ++i)
1548 {
1549 // Elevation from -PI/2 to PI/2
1550 const RealType elevation = (static_cast<RealType>(i) / el_denominator) * PI - (PI / 2.0);
1551 for (size_t j = 0; j < az_samples; ++j)
1552 {
1553 // Azimuth from -PI to PI
1554 const RealType azimuth = (static_cast<RealType>(j) / az_denominator) * 2.0 * PI - PI;
1555 const math::SVec3 sample_angle(1.0, azimuth, elevation);
1556 const RealType gain = ant->getGain(sample_angle, ref_angle, wavelength);
1557 data->gains[i * az_samples + j] = gain;
1558 max_gain = std::max(gain, max_gain);
1559 }
1560 }
1561
1562 data->max_gain = max_gain;
1563
1564 // Normalize the gains
1565 if (max_gain > 0)
1566 {
1567 for (size_t i = 0; i < total_samples; ++i)
1568 {
1569 data->gains[i] /= max_gain;
1570 }
1571 }
1572
1573 return data;
1574 }
1575 catch (const std::exception& e)
1576 {
1577 handle_api_exception(e, "fers_get_antenna_pattern");
1578 return nullptr;
1579 }
1580}
Abstract base class representing an antenna.
A class representing a vector in spherical coordinates.
double RealType
Type for real numbers.
Definition config.h:27
constexpr RealType PI
Mathematical constant π (pi).
Definition config.h:43
RealType c() noexcept
Get the speed of light.
Definition parameters.h:91
uint64_t SimId
64-bit Unique Simulation ID.
Definition sim_id.h:18
Represents a sampled 2D antenna gain pattern.
Definition api.h:550

References params::c(), logging::ERROR, antenna::Antenna::getGain(), handle_api_exception(), last_error_message, LOG, and PI.

+ Here is the call graph for this function:

◆ fers_get_interpolated_motion_path()

fers_interpolated_path_t * fers_get_interpolated_motion_path ( const fers_motion_waypoint_t waypoints,
size_t  waypoint_count,
fers_interp_type_t  interp_type,
size_t  num_points 
)

Calculates an interpolated motion path from a set of waypoints.

This function is a stateless utility that computes the path without needing a full simulation context. It is useful for UI previews.

Parameters
waypointsAn array of fers_motion_waypoint_t structs.
waypoint_countThe number of waypoints in the array.
interp_typeThe interpolation algorithm to use.
num_pointsThe desired number of points in the output interpolated path.
Returns
A pointer to a fers_interpolated_path_t struct containing the results. Returns NULL on failure. The caller owns the returned struct and must free it with fers_free_interpolated_motion_path.

Definition at line 1302 of file api.cpp.

1306{
1307 last_error_message.clear();
1308 if ((waypoints == nullptr) || waypoint_count == 0 || num_points == 0)
1309 {
1310 last_error_message = "Invalid arguments: waypoints cannot be null and counts must be > 0.";
1312 return nullptr;
1313 }
1315 {
1316 last_error_message = "Cubic interpolation requires at least 2 waypoints.";
1318 return nullptr;
1319 }
1320
1321 try
1322 {
1323 math::Path path;
1325
1326 for (size_t i = 0; i < waypoint_count; ++i)
1327 {
1328 math::Coord c;
1329 c.t = waypoints[i].time;
1330 c.pos.x = waypoints[i].x;
1331 c.pos.y = waypoints[i].y;
1332 c.pos.z = waypoints[i].z;
1333 path.addCoord(c);
1334 }
1335
1336 path.finalize();
1337
1338 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Public C API returns an owned path struct.
1340 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Public C API frees this array with the parent path.
1342 result_path->count = num_points;
1343
1344 const double start_time = waypoints[0].time;
1345 const double end_time = waypoints[waypoint_count - 1].time;
1346 const double duration = end_time - start_time;
1347
1348 // Handle static case separately
1349 if (waypoint_count < 2 || duration <= 0)
1350 {
1351 const math::Vec3 pos = path.getPosition(start_time);
1352 for (size_t i = 0; i < num_points; ++i)
1353 {
1354 result_path->points[i] = {pos.x, pos.y, pos.z, 0.0, 0.0, 0.0};
1355 }
1356 return result_path;
1357 }
1358
1359 const double time_step =
1360 duration / static_cast<double>(num_points > 1 ? num_points - 1 : static_cast<size_t>(1));
1361
1362 for (size_t i = 0; i < num_points; ++i)
1363 {
1364 const double t = start_time + static_cast<double>(i) * time_step;
1365 const math::Vec3 pos = path.getPosition(t);
1366 const math::Vec3 vel = path.getVelocity(t);
1367 result_path->points[i] = {pos.x, pos.y, pos.z, vel.x, vel.y, vel.z};
1368 }
1369
1370 return result_path;
1371 }
1372 catch (const std::exception& e)
1373 {
1374 handle_api_exception(e, "fers_get_interpolated_motion_path");
1375 return nullptr;
1376 }
1377}
math::Path::InterpType to_cpp_interp_type(const fers_interp_type_t type)
Definition api.cpp:1273
@ FERS_INTERP_CUBIC
Definition api.h:598
Represents a path with coordinates and allows for various interpolation methods.
Definition path.h:31
Vec3 getPosition(RealType t) const
Retrieves the position at a given time along the path.
Definition path.cpp:36
void setInterp(InterpType settype) noexcept
Changes the interpolation type.
Definition path.cpp:164
Vec3 getVelocity(RealType t) const
Retrieves the velocity at a given time along the path.
Definition path.cpp:60
void addCoord(const Coord &coord) noexcept
Adds a coordinate to the path.
Definition path.cpp:27
void finalize()
Finalizes the path, preparing it for interpolation.
Definition path.cpp:147
A class representing a vector in rectangular coordinates.
RealType x
The x component of the vector.
RealType z
The z component of the vector.
RealType y
The y component of the vector.
RealType c
A container for an array of interpolated motion path points.
Definition api.h:663
Represents a single interpolated point on a motion path.
Definition api.h:638
Represents a position in 3D space with an associated time.
Definition coord.h:24
RealType t
Time.
Definition coord.h:26

References math::Path::addCoord(), c, logging::ERROR, FERS_INTERP_CUBIC, math::Path::finalize(), math::Path::getPosition(), math::Path::getVelocity(), handle_api_exception(), last_error_message, LOG, math::Path::setInterp(), math::Coord::t, fers_motion_waypoint_t::time, to_cpp_interp_type(), fers_motion_waypoint_t::x, math::Vec3::x, fers_motion_waypoint_t::y, math::Vec3::y, fers_motion_waypoint_t::z, and math::Vec3::z.

+ Here is the call graph for this function:

◆ fers_get_interpolated_rotation_path()

fers_interpolated_rotation_path_t * fers_get_interpolated_rotation_path ( const fers_rotation_waypoint_t waypoints,
size_t  waypoint_count,
fers_interp_type_t  interp_type,
fers_angle_unit_t  angle_unit,
size_t  num_points 
)

Calculates an interpolated rotation path from a set of waypoints.

This function is a stateless utility for UI previews.

Parameters
waypointsAn array of fers_rotation_waypoint_t structs.
waypoint_countThe number of waypoints in the array.
interp_typeThe interpolation algorithm to use (STATIC, LINEAR, CUBIC).
angle_unitThe unit used by the waypoint angles and desired output angles.
num_pointsThe desired number of points in the output interpolated path.
Returns
A pointer to a fers_interpolated_rotation_path_t struct containing the results. Returns NULL on failure. The caller owns the returned struct and must free it with fers_free_interpolated_rotation_path.

Definition at line 1391 of file api.cpp.

1396{
1397 last_error_message.clear();
1398 last_warning_messages.clear();
1400 if ((waypoints == nullptr) || waypoint_count == 0 || num_points == 0)
1401 {
1402 last_error_message = "Invalid arguments: waypoints cannot be null and counts must be > 0.";
1404 return nullptr;
1405 }
1407 {
1408 last_error_message = "Cubic interpolation requires at least 2 waypoints.";
1410 return nullptr;
1411 }
1412
1413 try
1414 {
1415 const auto unit =
1417 math::RotationPath path;
1419
1420 for (size_t i = 0; i < waypoint_count; ++i)
1421 {
1424 std::format("rotation waypoint {}", i), "azimuth");
1427 std::format("rotation waypoint {}", i), "elevation");
1429 waypoints[i].azimuth, waypoints[i].elevation, waypoints[i].time, unit));
1430 }
1431
1432 path.finalize();
1433
1434 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Public C API returns an owned path struct.
1436 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): Public C API frees this array with the parent path.
1438 result_path->count = num_points;
1439
1440 const double start_time = waypoints[0].time;
1441 const double end_time = waypoints[waypoint_count - 1].time;
1442 const double duration = end_time - start_time;
1443
1444 // Handle static case separately
1445 if (waypoint_count < 2 || duration <= 0)
1446 {
1447 const math::SVec3 rot = path.getPosition(start_time);
1448 for (size_t i = 0; i < num_points; ++i)
1449 {
1453 }
1454 return result_path;
1455 }
1456
1457 const double time_step =
1458 duration / static_cast<double>(num_points > 1 ? num_points - 1 : static_cast<size_t>(1));
1459
1460 for (size_t i = 0; i < num_points; ++i)
1461 {
1462 const double t = start_time + static_cast<double>(i) * time_step;
1463 const math::SVec3 rot = path.getPosition(t);
1464
1468 }
1469
1470 return result_path;
1471 }
1472 catch (const std::exception& e)
1473 {
1475 handle_api_exception(e, "fers_get_interpolated_rotation_path");
1476 return nullptr;
1477 }
1478}
math::RotationPath::InterpType to_cpp_rot_interp_type(const fers_interp_type_t type)
Definition api.cpp:1287
@ FERS_ANGLE_UNIT_RAD
Definition api.h:607
Manages rotational paths with different interpolation techniques.
void finalize()
Finalizes the rotation path for interpolation.
void setInterp(InterpType setinterp) noexcept
Sets the interpolation type for the path.
SVec3 getPosition(RealType t) const
Gets the rotational position at a given time.
void addCoord(const RotationCoord &coord) noexcept
Adds a rotation coordinate to the path.
@ Radians
Compass azimuth and elevation expressed in radians.
@ Degrees
Compass azimuth and elevation expressed in degrees.
RealType internal_elevation_to_external(const RealType elevation, const params::RotationAngleUnit unit) noexcept
Converts an internal elevation angle to the external unit.
math::RotationCoord external_rotation_to_internal(const RealType azimuth, const RealType elevation, const RealType time, const params::RotationAngleUnit unit) noexcept
Converts external compass azimuth/elevation into internal rotation coordinates.
RealType internal_azimuth_to_external(const RealType azimuth, const params::RotationAngleUnit unit) noexcept
Converts an internal azimuth angle to the external compass convention.
void maybe_warn_about_rotation_value(const RealType value, const params::RotationAngleUnit declared_unit, const ValueKind kind, const std::string_view source, const std::string_view owner, const std::string_view field)
Emits or captures a warning when a rotation value likely uses the wrong unit.
A container for an array of interpolated rotation path points.
Definition api.h:673
Represents a single interpolated point on a rotation path.
Definition api.h:652

References math::RotationPath::addCoord(), serial::rotation_warning_utils::Angle, math::SVec3::azimuth, serial::rotation_warning_utils::clear_captured_warnings(), params::Degrees, math::SVec3::elevation, logging::ERROR, serial::rotation_angle_utils::external_rotation_to_internal(), FERS_ANGLE_UNIT_RAD, FERS_INTERP_CUBIC, math::RotationPath::finalize(), math::RotationPath::getPosition(), handle_api_exception(), serial::rotation_angle_utils::internal_azimuth_to_external(), serial::rotation_angle_utils::internal_elevation_to_external(), last_error_message, last_warning_messages, LOG, serial::rotation_warning_utils::maybe_warn_about_rotation_value(), params::Radians, math::RotationPath::setInterp(), fers_rotation_waypoint_t::time, and to_cpp_rot_interp_type().

+ Here is the call graph for this function:

◆ fers_get_last_error_message()

char * fers_get_last_error_message ( )

Retrieves the last error message that occurred on the current thread.

Because C++ exceptions cannot safely propagate across the FFI boundary into other languages, this function provides the standard C-style error reporting mechanism. The error state is stored in a thread-local variable to ensure that concurrent API calls from different threads do not overwrite each other's error messages. The error is cleared at the start of each fallible API call.

Note
Memory Management: The returned string's ownership is transferred to the caller. It MUST be freed using fers_free_string() to prevent memory leaks.
Returns
A dynamically allocated, null-terminated C-string containing the last error message, or NULL if no error has occurred.

Definition at line 1084 of file api.cpp.

1085{
1086 if (last_error_message.empty())
1087 {
1088 return nullptr; // No error to report
1089 }
1090 // `strdup` allocates with `malloc`, which is part of the C standard ABI,
1091 // making it safe to transfer ownership across the FFI boundary. The caller
1092 // must then free this memory using `fers_free_string`.
1093 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc): C ABI string ownership is freed by `fers_free_string`.
1094 return strdup(last_error_message.c_str());
1095}

References last_error_message.

◆ fers_get_last_output_metadata_json()

char * fers_get_last_output_metadata_json ( fers_context_t context)

Returns JSON metadata for the most recent simulation output files.

The returned JSON describes generated HDF5 file structure and sample ranges. The caller owns the returned string and must free it with fers_free_string. If no simulation has completed yet, the returned JSON contains an empty files array.

Parameters
contextA valid fers_context_t handle.
Returns
A heap-allocated JSON string, or NULL on error.

Definition at line 758 of file api.cpp.

759{
760 last_error_message.clear();
761 if (context == nullptr)
762 {
763 last_error_message = "Invalid context provided to fers_get_last_output_metadata_json.";
765 return nullptr;
766 }
767
768 const auto* ctx = context;
769 try
770 {
771 const std::string json_str = ctx->getLastOutputMetadataJson();
772 return strdup(json_str.c_str());
773 }
774 catch (const std::exception& e)
775 {
776 handle_api_exception(e, "fers_get_last_output_metadata_json");
777 return nullptr;
778 }
779}

References logging::ERROR, FersContext::getLastOutputMetadataJson(), handle_api_exception(), last_error_message, and LOG.

+ Here is the call graph for this function:

◆ fers_get_last_warning_messages_json()

char * fers_get_last_warning_messages_json ( )

Returns the last deduplicated rotation-unit warning list for the calling thread as JSON.

The returned value is a JSON array of strings. It is populated by successful XML/JSON load and update calls that detect suspicious rotation values. The caller owns the string and must free it with fers_free_string().

Returns
A dynamically allocated JSON array string, or NULL if no warnings are available.

Definition at line 1097 of file api.cpp.

1098{
1099 if (last_warning_messages.empty())
1100 {
1101 return nullptr;
1102 }
1103
1104 const std::string warning_json = nlohmann::json(last_warning_messages).dump();
1105 last_warning_messages.clear();
1106 return strdup(warning_json.c_str());
1107}

References last_warning_messages.

◆ fers_get_log_level()

fers_log_level_t fers_get_log_level ( )

Returns the current internal logger level.

Definition at line 379 of file api.cpp.

379{ return map_internal_log_level(logging::logger.getLevel()); }
static fers_log_level_t map_internal_log_level(logging::Level level)
Definition api.cpp:152

References logging::logger, and map_internal_log_level().

+ Here is the call graph for this function:

◆ fers_get_memory_projection_json()

char * fers_get_memory_projection_json ( fers_context_t context)

Returns a JSON projection of simulation startup memory and HDF5 payload size.

The projection includes phase-noise lookup memory, streaming I/Q buffer memory, rendered HDF5 payload size, current resident memory not attributed to streaming I/Q buffers where available, and an aggregate projected total. The caller owns the returned string and must free it with fers_free_string.

Parameters
contextA valid fers_context_t handle.
Returns
A heap-allocated JSON string, or NULL on error.

Definition at line 781 of file api.cpp.

782{
783 last_error_message.clear();
784 if (context == nullptr)
785 {
786 last_error_message = "Invalid context provided to fers_get_memory_projection_json.";
788 return nullptr;
789 }
790
791 auto* ctx = context;
792
793 try
794 {
795 const auto projection = core::projectSimulationMemory(*ctx->getWorld());
797 return strdup(json_str.c_str());
798 }
799 catch (const std::exception& e)
800 {
801 handle_api_exception(e, "fers_get_memory_projection_json");
802 return nullptr;
803 }
804}
std::string memoryProjectionToJsonString(const SimulationMemoryProjection &projection)
Serializes a simulation memory projection as JSON.
SimulationMemoryProjection projectSimulationMemory(const World &world)
Projects startup memory and rendered-output sizes for a simulation world.

References logging::ERROR, handle_api_exception(), last_error_message, LOG, core::memoryProjectionToJsonString(), and core::projectSimulationMemory().

+ Here is the call graph for this function:

◆ fers_get_scenario_as_json()

char * fers_get_scenario_as_json ( fers_context_t context)

Serializes the current simulation scenario into a JSON string.

This function is the primary method for the UI to retrieve the full state of the simulation. JSON is used as the interchange format because it is lightweight, human-readable, and natively supported by web technologies, making it trivial to parse and use in the React/TypeScript frontend.

Note
Memory Management: The returned string is allocated by this library and its ownership is transferred to the caller. It is crucial to free this string using fers_free_string() to prevent memory leaks.
Parameters
contextA valid fers_context_t handle.
Returns
A dynamically allocated, null-terminated C-string containing the JSON representation of the scenario. Returns NULL on failure.

Definition at line 701 of file api.cpp.

702{
703 last_error_message.clear();
704 if (context == nullptr)
705 {
706 last_error_message = "Invalid context provided to fers_get_scenario_as_json.";
708 return nullptr;
709 }
710
711 const auto* ctx = context;
712 try
713 {
714 const nlohmann::json j = serial::world_to_json(*ctx->getWorld());
715 const std::string json_str = j.dump(2);
716 // A heap-allocated copy of the string is returned. This is necessary
717 // to transfer ownership of the memory across the FFI boundary to a
718 // client that will free it using `fers_free_string`.
719 return strdup(json_str.c_str());
720 }
721 catch (const std::exception& e)
722 {
723 handle_api_exception(e, "fers_get_scenario_as_json");
724 return nullptr;
725 }
726}
nlohmann::json world_to_json(const core::World &world)
Serializes the entire simulation world into a nlohmann::json object.

References logging::ERROR, handle_api_exception(), last_error_message, LOG, and serial::world_to_json().

+ Here is the call graph for this function:

◆ fers_get_scenario_as_xml()

char * fers_get_scenario_as_xml ( fers_context_t context)

Serializes the current simulation scenario into a FERS XML string.

This function enables exporting the in-memory state back into the standard FERS XML file format. This is essential for interoperability with legacy tools and for allowing a user to save a scenario that was created or modified in the UI.

Note
Memory Management: The returned string is dynamically allocated and its ownership is transferred to the caller. It must be freed using fers_free_string() to prevent memory leaks.
Parameters
contextA valid fers_context_t handle.
Returns
A dynamically allocated, null-terminated C-string containing the XML representation of the scenario. Returns NULL on failure.

Definition at line 728 of file api.cpp.

729{
730 last_error_message.clear();
731 if (context == nullptr)
732 {
733 last_error_message = "Invalid context provided to fers_get_scenario_as_xml.";
735 return nullptr;
736 }
737
738 const auto* ctx = context;
739 try
740 {
741 const std::string xml_str = serial::world_to_xml_string(*ctx->getWorld());
742 if (xml_str.empty())
743 {
744 throw std::runtime_error("XML serialization resulted in an empty string.");
745 }
746 // `strdup` is used to create a heap-allocated string that can be safely
747 // passed across the FFI boundary. The client is responsible for freeing
748 // this memory with `fers_free_string`.
749 return strdup(xml_str.c_str());
750 }
751 catch (const std::exception& e)
752 {
753 handle_api_exception(e, "fers_get_scenario_as_xml");
754 return nullptr;
755 }
756}
std::string world_to_xml_string(const core::World &world)
Serializes the entire simulation world into an XML formatted string.

References logging::ERROR, handle_api_exception(), last_error_message, LOG, and serial::world_to_xml_string().

+ Here is the call graph for this function:

◆ fers_get_version()

const char * fers_get_version ( void  )

Returns the library version string.

The returned pointer remains valid for the lifetime of the process and must not be freed by the caller.

Definition at line 377 of file api.cpp.

377{ return FERS_VERSION_STRING; }

Referenced by core::showHelp().

+ Here is the caller graph for this function:

◆ fers_load_scenario_from_xml_file()

int fers_load_scenario_from_xml_file ( fers_context_t context,
const char xml_filepath,
int  validate 
)

Loads a scenario into the context from a FERS XML file.

This is the standard method for initializing a simulation context from a file on disk. It is essential for interoperability with the CLI and legacy workflows that rely on the FERS XML format.

Parameters
contextA valid fers_context_t handle.
xml_filepathA null-terminated UTF-8 string for the input XML file path.
validateA boolean (0 or 1) indicating whether to validate the XML against the embedded FERS schema. Validation is recommended to ensure scenario correctness.
Returns
0 on success, a non-zero error code on failure. Use fers_get_last_error_message() to retrieve error details.

Definition at line 605 of file api.cpp.

606{
607 last_error_message.clear();
609 if ((context == nullptr) || (xml_filepath == nullptr))
610 {
611 last_error_message = "Invalid arguments: context or xml_filepath is NULL.";
614 return -1;
615 }
616
617 auto* ctx = context;
618 try
619 {
620 // Set default output directory to the scenario file's directory
621 std::filesystem::path const p(xml_filepath);
622 auto parent = p.parent_path();
623 if (parent.empty())
624 parent = ".";
625 ctx->setOutputDir(parent.string());
626
627 serial::parseSimulation(xml_filepath, ctx->getWorld(), static_cast<bool>(validate), ctx->getMasterSeeder());
628
629 // After parsing, seed the master random number generator. This is done
630 // to ensure simulation reproducibility. If the scenario specifies a seed,
631 // it is used; otherwise, a non-deterministic seed is generated so that
632 // subsequent runs are unique by default.
633 if (params::params.random_seed)
634 {
635 LOG(logging::Level::INFO, "Using master seed from scenario file: {}", *params::params.random_seed);
636 ctx->getMasterSeeder().seed(*params::params.random_seed);
637 }
638 else
639 {
640 const auto seed = std::random_device{}();
641 LOG(logging::Level::INFO, "No master seed provided in scenario. Using random_device seed: {}", seed);
643 ctx->getMasterSeeder().seed(seed);
644 }
646 return 0; // Success
647 }
648 catch (const std::exception& e)
649 {
651 handle_api_exception(e, "fers_load_scenario_from_xml_file");
652 return 1; // Error
653 }
654}
static void begin_warning_capture() noexcept
Definition api.cpp:78
static void complete_warning_capture()
Definition api.cpp:84
@ INFO
Info level for informational messages.
Parameters params
Global simulation parameter state.
Definition parameters.h:85
void parseSimulation(const std::string &filename, core::World *world, const bool validate, std::mt19937 &masterSeeder)
Parses a simulation configuration from an XML file.
std::optional< unsigned > random_seed
Random seed for simulation.
Definition parameters.h:70

References begin_warning_capture(), complete_warning_capture(), discard_warning_capture(), logging::ERROR, handle_api_exception(), logging::INFO, last_error_message, LOG, params::params, serial::parseSimulation(), and params::Parameters::random_seed.

+ Here is the call graph for this function:

◆ fers_load_scenario_from_xml_string()

int fers_load_scenario_from_xml_string ( fers_context_t context,
const char xml_content,
int  validate 
)

Loads a scenario into the context from a FERS XML string.

This function provides a way to load a scenario from an in-memory string, avoiding file I/O. It is useful for test harnesses or for UIs that manage scenarios as text content before parsing.

Parameters
contextA valid fers_context_t handle.
xml_contentA null-terminated UTF-8 string containing the FERS scenario in XML format.
validateA boolean (0 or 1) indicating whether to validate the XML against the embedded FERS schema.
Returns
0 on success, a non-zero error code on failure. Use fers_get_last_error_message() to retrieve error details.

Definition at line 656 of file api.cpp.

657{
658 last_error_message.clear();
660 if ((context == nullptr) || (xml_content == nullptr))
661 {
662 last_error_message = "Invalid arguments: context or xml_content is NULL.";
665 return -1;
666 }
667
668 auto* ctx = context;
669 try
670 {
671 serial::parseSimulationFromString(xml_content, ctx->getWorld(), static_cast<bool>(validate),
672 ctx->getMasterSeeder());
673
674 // After parsing, seed the master random number generator. This ensures
675 // that if the scenario provides a seed, the simulation will be
676 // reproducible. If not, a random seed is used to ensure unique runs.
677 if (params::params.random_seed)
678 {
679 LOG(logging::Level::INFO, "Using master seed from scenario string: {}", *params::params.random_seed);
680 ctx->getMasterSeeder().seed(*params::params.random_seed);
681 }
682 else
683 {
684 const auto seed = std::random_device{}();
685 LOG(logging::Level::INFO, "No master seed provided in scenario. Using random_device seed: {}", seed);
687 ctx->getMasterSeeder().seed(seed);
688 }
689
691 return 0; // Success
692 }
693 catch (const std::exception& e)
694 {
696 handle_api_exception(e, "fers_load_scenario_from_xml_string");
697 return 1; // Parsing or logic error
698 }
699}
void parseSimulationFromString(const std::string &xmlContent, core::World *world, const bool validate, std::mt19937 &masterSeeder)
Parses a simulation configuration directly from an XML string in memory.

References begin_warning_capture(), complete_warning_capture(), discard_warning_capture(), logging::ERROR, handle_api_exception(), logging::INFO, last_error_message, LOG, params::params, serial::parseSimulationFromString(), and params::Parameters::random_seed.

+ Here is the call graph for this function:

◆ fers_log()

void fers_log ( fers_log_level_t  level,
const char message 
)

Submits a log message to the library's unified logging system.

This ensures CLI messages match the format (timestamps, alignment) of library messages.

Definition at line 392 of file api.cpp.

393{
394 if (message == nullptr)
395 return;
396 // We pass a default source_location because C-API calls don't provide C++ source info
397 logging::logger.log(map_api_log_level(level), message, std::source_location::current());
398}
void log(Level level, const std::string &message, const std::source_location &location=std::source_location::current()) noexcept
Logs a message with a specific log level and source location.
Definition logging.cpp:45

References logging::Logger::log(), logging::logger, and map_api_log_level().

+ Here is the call graph for this function:

◆ fers_run_simulation()

int fers_run_simulation ( fers_context_t context,
fers_progress_callback_t  callback,
void user_data 
)

Runs the simulation defined in the provided context.

This function is synchronous and will block the calling thread until the simulation is complete. This design keeps the API simple. For use in a responsive UI, it is the responsibility of the caller (e.g., the Tauri backend) to invoke this function on a separate worker thread to avoid freezing the user interface.

Parameters
contextA valid fers_context_t handle containing a loaded scenario.
callbackA function pointer to a progress callback. Can be NULL.
user_dataAn opaque pointer passed to the callback function.
Returns
0 on success, a non-zero error code on failure. Use fers_get_last_error_message() to retrieve error details.

Definition at line 1211 of file api.cpp.

1212{
1213 return run_simulation_common(
1214 SimulationRunRequest{.context = context,
1215 .progress_callback = callback,
1216 .progress_user_data = user_data,
1217 .cancel_callback = nullptr,
1218 .cancel_user_data = nullptr,
1219 .vita49_telemetry_callback = nullptr,
1220 .vita49_telemetry_user_data = nullptr,
1221 .function_name = "fers_run_simulation",
1222 .invalid_context_message = "Invalid context provided to fers_run_simulation."});
1223}

◆ fers_run_simulation_ex()

int fers_run_simulation_ex ( fers_context_t context,
fers_progress_callback_t  progress_callback,
void progress_user_data,
fers_cancel_callback_t  cancel_callback,
void cancel_user_data,
fers_vita49_telemetry_callback_t  vita49_telemetry_callback,
void vita49_telemetry_user_data 
)

Runs the simulation with optional progress, cancellation, and VITA telemetry callbacks.

Return values match fers_run_simulation, except 2 means the run was cooperatively cancelled after output finalization and metadata collection.

Parameters
contextA valid fers_context_t handle containing a loaded scenario.
progress_callbackOptional progress callback. Can be NULL.
progress_user_dataOpaque pointer passed to the progress callback.
cancel_callbackOptional cancellation callback. Can be NULL.
cancel_user_dataOpaque pointer passed to the cancellation callback.
vita49_telemetry_callbackOptional VITA live telemetry callback. Can be NULL.
vita49_telemetry_user_dataOpaque pointer passed to the VITA telemetry callback.
Returns
0 on success, 2 on cancellation, a non-zero error code on failure.

Definition at line 1225 of file api.cpp.

1228{
1229 return run_simulation_common(
1230 SimulationRunRequest{.context = context,
1231 .progress_callback = progress_callback,
1232 .progress_user_data = progress_user_data,
1233 .cancel_callback = cancel_callback,
1234 .cancel_user_data = cancel_user_data,
1235 .vita49_telemetry_callback = vita49_telemetry_callback,
1236 .vita49_telemetry_user_data = vita49_telemetry_user_data,
1237 .function_name = "fers_run_simulation_ex",
1238 .invalid_context_message = "Invalid context provided to fers_run_simulation_ex."});
1239}

◆ fers_set_log_callback()

void fers_set_log_callback ( fers_log_callback_t  callback,
void user_data 
)

Registers a callback for formatted log lines.

Pass NULL as callback to disable log callbacks.

Definition at line 381 of file api.cpp.

382{
383 {
384 std::scoped_lock const lock(log_callback_mutex);
387 }
388
390}
void setCallback(Callback callback, void *user_data) noexcept
Sets an optional callback that receives each formatted log line.
Definition logging.cpp:83

References logging::logger, and logging::Logger::setCallback().

+ Here is the call graph for this function:

◆ fers_set_output_directory()

int fers_set_output_directory ( fers_context_t context,
const char out_dir 
)

Sets the output directory for simulation results.

Parameters
contextA valid fers_context_t handle.
out_dirA null-terminated UTF-8 string for the output directory path.
Returns
0 on success, non-zero on error.

Definition at line 419 of file api.cpp.

420{
421 last_error_message.clear();
422 if ((context == nullptr) || (out_dir == nullptr))
423 {
424 set_api_error("Invalid arguments: context or out_dir is NULL.");
425 return -1;
426 }
427 auto* ctx = context;
428 try
429 {
430 ctx->setOutputDir(out_dir);
431 return 0;
432 }
433 catch (const std::exception& e)
434 {
435 handle_api_exception(e, "fers_set_output_directory");
436 return 1;
437 }
438}

References handle_api_exception(), last_error_message, and FersContext::setOutputDir().

+ Here is the call graph for this function:

◆ fers_set_thread_count()

int fers_set_thread_count ( unsigned  num_threads)

Sets the number of worker threads for the simulation.

Parameters
num_threadsThe number of threads to use.
Returns
0 on success, non-zero on error. This function clears any previous thread-local error message at entry, like the other fallible API calls.

Definition at line 400 of file api.cpp.

401{
402 last_error_message.clear();
403 try
404 {
405 if (auto res = params::setThreads(num_threads); !res)
406 {
407 last_error_message = res.error();
408 return 1;
409 }
410 return 0;
411 }
412 catch (const std::exception& e)
413 {
414 handle_api_exception(e, "fers_set_thread_count");
415 return 1;
416 }
417}
std::expected< void, std::string > setThreads(const unsigned threads) noexcept
Set the number of worker threads.
Definition parameters.h:293

References handle_api_exception(), last_error_message, and params::setThreads().

+ Here is the call graph for this function:

◆ fers_set_vita49_epoch_unix_nanoseconds()

int fers_set_vita49_epoch_unix_nanoseconds ( fers_context_t context,
const std::uint64_t  epoch_unix_nanoseconds 
)

Definition at line 526 of file api.cpp.

527{
528 last_error_message.clear();
529 if (context == nullptr)
530 {
531 set_api_error("Invalid arguments: context is NULL.");
532 return -1;
533 }
534 if (!is_valid_vita49_epoch(epoch_unix_nanoseconds))
535 {
536 set_api_error("Invalid VITA49 epoch: value must fit the VRT 32-bit UTC seconds timestamp field.");
537 return 1;
538 }
539
540 auto* ctx = context;
541 core::OutputConfig config = ctx->getOutputConfig();
542 config.vita49.epoch_unix_nanoseconds = epoch_unix_nanoseconds;
543 ctx->setOutputConfig(std::move(config));
544 return 0;
545}

References core::Vita49OutputConfig::epoch_unix_nanoseconds, last_error_message, and core::OutputConfig::vita49.

◆ fers_set_vita49_fullscale()

int fers_set_vita49_fullscale ( fers_context_t context,
double  fullscale 
)

Sets the fixed ADC full-scale value used by the FERS VITA 49.2 int16 IQ profile.

VITA mode requires a positive finite full-scale before simulation starts. HDF5 output keeps its existing full-buffer scaling behavior.

Parameters
contextA valid fers_context_t handle.
fullscalePositive finite full-scale value.
Returns
0 on success, non-zero on error.

Definition at line 505 of file api.cpp.

506{
507 last_error_message.clear();
508 if (context == nullptr)
509 {
510 set_api_error("Invalid arguments: context is NULL.");
511 return -1;
512 }
513 if (!is_valid_vita49_fullscale(fullscale))
514 {
515 set_api_error("Invalid VITA49 fullscale: value must be positive and finite.");
516 return 1;
517 }
518
519 auto* ctx = context;
520 core::OutputConfig config = ctx->getOutputConfig();
521 config.vita49.adc_fullscale = static_cast<RealType>(fullscale);
522 ctx->setOutputConfig(std::move(config));
523 return 0;
524}

References core::Vita49OutputConfig::adc_fullscale, last_error_message, and core::OutputConfig::vita49.

◆ fers_set_vita49_max_udp_payload()

int fers_set_vita49_max_udp_payload ( fers_context_t context,
const std::uint16_t  max_udp_payload 
)

Definition at line 547 of file api.cpp.

548{
549 last_error_message.clear();
550 if (context == nullptr)
551 {
552 set_api_error("Invalid arguments: context is NULL.");
553 return -1;
554 }
555 if (!is_valid_vita49_max_payload(max_udp_payload))
556 {
557 set_api_error("Invalid VITA49 max UDP payload: value must be between 64 and 65507 bytes.");
558 return 1;
559 }
560
561 auto* ctx = context;
562 core::OutputConfig config = ctx->getOutputConfig();
563 config.vita49.max_udp_payload = max_udp_payload;
564 ctx->setOutputConfig(std::move(config));
565 return 0;
566}

References last_error_message, core::Vita49OutputConfig::max_udp_payload, and core::OutputConfig::vita49.

◆ fers_set_vita49_packet_trace_enabled()

int fers_set_vita49_packet_trace_enabled ( fers_context_t context,
int  enabled 
)

Enables or disables FERS VITA 49.2 packet trace telemetry.

Stream counter telemetry is unaffected. Disabling packet trace telemetry avoids per-packet diagnostic record creation for UI runs that only need live counters.

Parameters
contextA valid fers_context_t handle.
enabledNon-zero to enable packet trace telemetry, zero to disable it.
Returns
0 on success, non-zero on error.

Definition at line 589 of file api.cpp.

590{
591 last_error_message.clear();
592 if (context == nullptr)
593 {
594 set_api_error("Invalid arguments: context is NULL.");
595 return -1;
596 }
597
598 auto* ctx = context;
599 core::OutputConfig config = ctx->getOutputConfig();
600 config.vita49.packet_trace_enabled = enabled != 0;
601 ctx->setOutputConfig(std::move(config));
602 return 0;
603}

References last_error_message, core::Vita49OutputConfig::packet_trace_enabled, and core::OutputConfig::vita49.

◆ fers_set_vita49_queue_depth()

int fers_set_vita49_queue_depth ( fers_context_t context,
const std::uint32_t  queue_depth 
)

Definition at line 568 of file api.cpp.

569{
570 last_error_message.clear();
571 if (context == nullptr)
572 {
573 set_api_error("Invalid arguments: context is NULL.");
574 return -1;
575 }
576 if (queue_depth == 0)
577 {
578 set_api_error("Invalid VITA49 queue depth: value must be greater than zero.");
579 return 1;
580 }
581
582 auto* ctx = context;
583 core::OutputConfig config = ctx->getOutputConfig();
584 config.vita49.queue_depth = queue_depth;
585 ctx->setOutputConfig(std::move(config));
586 return 0;
587}

References last_error_message, core::Vita49OutputConfig::queue_depth, and core::OutputConfig::vita49.

◆ fers_update_antenna_from_json()

int fers_update_antenna_from_json ( fers_context_t context,
const char json 
)

Updates a single antenna from JSON without full context recreation.

Parameters
contextA valid fers_context_t handle.
jsonThe JSON string for the antenna.
Returns
0 on success, non-zero on failure.

Definition at line 867 of file api.cpp.

868{
869 last_error_message.clear();
870 if ((context == nullptr) || (json == nullptr))
871 return -1;
872 auto* ctx = context;
873 try
874 {
875 auto j = nlohmann::json::parse(json);
876 auto id = j.at("id").is_string() ? std::stoull(j.at("id").get<std::string>()) : j.at("id").get<uint64_t>();
877 auto* ant = ctx->getWorld()->findAntenna(id);
878 if (ant == nullptr)
879 {
880 last_error_message = "Antenna not found";
881 return 1;
882 }
884 return 0;
885 }
886 catch (const std::exception& e)
887 {
888 handle_api_exception(e, "fers_update_antenna_from_json");
889 return 1;
890 }
891}
void update_antenna_from_json(const nlohmann::json &j, antenna::Antenna *ant, core::World &world)
Updates an antenna from JSON without full context recreation.

References handle_api_exception(), last_error_message, and serial::update_antenna_from_json().

+ Here is the call graph for this function:

◆ fers_update_monostatic_from_json()

int fers_update_monostatic_from_json ( fers_context_t context,
const char json 
)

Updates a monostatic radar from JSON without full context recreation.

Parameters
contextA valid fers_context_t handle.
jsonThe JSON string for the monostatic component.
Returns
0 on success, non-zero on failure.

Definition at line 991 of file api.cpp.

992{
993 last_error_message.clear();
994 if ((context == nullptr) || (json == nullptr))
995 return -1;
996 auto* ctx = context;
997 try
998 {
999 auto j = nlohmann::json::parse(json);
1000 uint64_t const tx_id =
1001 j.at("tx_id").is_string() ? std::stoull(j.at("tx_id").get<std::string>()) : j.at("tx_id").get<uint64_t>();
1002 uint64_t const rx_id =
1003 j.at("rx_id").is_string() ? std::stoull(j.at("rx_id").get<std::string>()) : j.at("rx_id").get<uint64_t>();
1004 auto* tx = ctx->getWorld()->findTransmitter(tx_id);
1005 auto* rx = ctx->getWorld()->findReceiver(rx_id);
1006 if ((tx == nullptr) || (rx == nullptr))
1007 {
1008 last_error_message = "Monostatic components not found";
1009 return 1;
1010 }
1011 serial::update_monostatic_from_json(j, tx, rx, *ctx->getWorld(), ctx->getMasterSeeder());
1012 return 0;
1013 }
1014 catch (const std::exception& e)
1015 {
1016 handle_api_exception(e, "fers_update_monostatic_from_json");
1017 return 1;
1018 }
1019}
void update_monostatic_from_json(const nlohmann::json &j, radar::Transmitter *tx, radar::Receiver *rx, core::World &world, std::mt19937 &masterSeeder)
Updates a monostatic radar from JSON without full context recreation.

References handle_api_exception(), last_error_message, and serial::update_monostatic_from_json().

+ Here is the call graph for this function:

◆ fers_update_parameters_from_json()

int fers_update_parameters_from_json ( fers_context_t context,
const char json 
)

Updates the global simulation parameters from JSON without full context recreation.

Parameters
contextA valid fers_context_t handle.
jsonThe JSON string for the parameters.
Returns
0 on success, non-zero on failure.

Definition at line 842 of file api.cpp.

843{
844 last_error_message.clear();
846 if ((context == nullptr) || (json == nullptr))
847 {
849 return -1;
850 }
851 auto* ctx = context;
852 try
853 {
854 auto j = nlohmann::json::parse(json);
855 serial::update_parameters_from_json(j, ctx->getMasterSeeder());
857 return 0;
858 }
859 catch (const std::exception& e)
860 {
862 handle_api_exception(e, "fers_update_parameters_from_json");
863 return 1;
864 }
865}
void update_parameters_from_json(const nlohmann::json &j, std::mt19937 &masterSeeder)
Updates global simulation parameters from JSON.

References begin_warning_capture(), complete_warning_capture(), discard_warning_capture(), handle_api_exception(), last_error_message, and serial::update_parameters_from_json().

+ Here is the call graph for this function:

◆ fers_update_platform_from_json()

int fers_update_platform_from_json ( fers_context_t context,
uint64_t  id,
const char json 
)

Updates a single platform's paths and name from JSON without full context recreation.

Parameters
contextA valid fers_context_t handle.
idThe unique ID of the platform.
jsonThe JSON string for the platform.
Returns
0 on success, non-zero on failure.

Definition at line 806 of file api.cpp.

807{
808 last_error_message.clear();
810 if ((context == nullptr) || (json == nullptr))
811 {
813 return -1;
814 }
815 auto* ctx = context;
816 try
817 {
818 auto* p = ctx->getWorld()->findPlatform(id);
819 if (p == nullptr)
820 {
821 last_error_message = "Platform not found";
823 return 1;
824 }
825 auto j = nlohmann::json::parse(json);
827 if (j.contains("name"))
828 {
829 p->setName(j.at("name").get<std::string>());
830 }
832 return 0;
833 }
834 catch (const std::exception& e)
835 {
837 handle_api_exception(e, "fers_update_platform_from_json");
838 return 1;
839 }
840}
void update_platform_paths_from_json(const nlohmann::json &j, radar::Platform *plat)
Updates a platform's motion and rotation paths from JSON.

References begin_warning_capture(), complete_warning_capture(), discard_warning_capture(), core::World::findPlatform(), FersContext::getWorld(), handle_api_exception(), last_error_message, and serial::update_platform_paths_from_json().

+ Here is the call graph for this function:

◆ fers_update_receiver_from_json()

int fers_update_receiver_from_json ( fers_context_t context,
uint64_t  id,
const char json 
)

Updates a single receiver from JSON without full context recreation.

Parameters
contextA valid fers_context_t handle.
idThe unique ID of the receiver.
jsonThe JSON string for the receiver.
Returns
0 on success, non-zero on failure.

Definition at line 941 of file api.cpp.

942{
943 last_error_message.clear();
944 if ((context == nullptr) || (json == nullptr))
945 return -1;
946 auto* ctx = context;
947 try
948 {
949 auto* rx = ctx->getWorld()->findReceiver(id);
950 if (rx == nullptr)
951 {
952 last_error_message = "Receiver not found";
953 return 1;
954 }
955 auto j = nlohmann::json::parse(json);
956 serial::update_receiver_from_json(j, rx, *ctx->getWorld(), ctx->getMasterSeeder());
957 return 0;
958 }
959 catch (const std::exception& e)
960 {
961 handle_api_exception(e, "fers_update_receiver_from_json");
962 return 1;
963 }
964}
void update_receiver_from_json(const nlohmann::json &j, radar::Receiver *rx, core::World &world, std::mt19937 &)
Updates a receiver from JSON without full context recreation.

References core::World::findReceiver(), FersContext::getWorld(), handle_api_exception(), last_error_message, and serial::update_receiver_from_json().

+ Here is the call graph for this function:

◆ fers_update_scenario_from_json()

int fers_update_scenario_from_json ( fers_context_t context,
const char scenario_json 
)

Updates the simulation scenario from a JSON string.

This is the primary method for the UI to push its state back to the C++ core. It performs a full replacement of the existing scenario.

Parameters
contextA valid fers_context_t handle.
scenario_jsonA null-terminated UTF-8 string containing the FERS scenario in JSON format.
Returns
0 on success. 1 on generic logic error. 2 on JSON parsing/schema validation error. Use fers_get_last_error_message() to retrieve error details.

Definition at line 1045 of file api.cpp.

1046{
1047 last_error_message.clear();
1049 if ((context == nullptr) || (scenario_json == nullptr))
1050 {
1051 last_error_message = "Invalid arguments: context or scenario_json is NULL.";
1054 return -1;
1055 }
1056
1057 auto* ctx = context;
1058 try
1059 {
1060 const nlohmann::json j = nlohmann::json::parse(scenario_json);
1061 serial::json_to_world(j, *ctx->getWorld(), ctx->getMasterSeeder());
1063
1064 return 0; // Success
1065 }
1066 catch (const nlohmann::json::exception& e)
1067 {
1068 // A specific catch block for JSON errors is used to provide more
1069 // detailed feedback to the client (e.g., the UI), which can help
1070 // developers diagnose schema or data format issues more easily.
1071 last_error_message = "JSON parsing/deserialization error: " + std::string(e.what());
1072 LOG(logging::Level::ERROR, "API Error in {}: {}", "fers_update_scenario_from_json", last_error_message);
1074 return 2; // JSON error
1075 }
1076 catch (const std::exception& e)
1077 {
1079 handle_api_exception(e, "fers_update_scenario_from_json");
1080 return 1; // Generic error
1081 }
1082}
void json_to_world(const nlohmann::json &j, core::World &world, std::mt19937 &masterSeeder)
Deserializes a nlohmann::json object and reconstructs the simulation world.

References begin_warning_capture(), complete_warning_capture(), discard_warning_capture(), logging::ERROR, handle_api_exception(), serial::json_to_world(), last_error_message, and LOG.

+ Here is the call graph for this function:

◆ fers_update_target_from_json()

int fers_update_target_from_json ( fers_context_t context,
uint64_t  id,
const char json 
)

Updates a single target from JSON without full context recreation.

Parameters
contextA valid fers_context_t handle.
idThe unique ID of the target.
jsonThe JSON string for the target.
Returns
0 on success, non-zero on failure.

Definition at line 966 of file api.cpp.

967{
968 last_error_message.clear();
969 if ((context == nullptr) || (json == nullptr))
970 return -1;
971 auto* ctx = context;
972 try
973 {
974 auto* tgt = ctx->getWorld()->findTarget(id);
975 if (tgt == nullptr)
976 {
977 last_error_message = "Target not found";
978 return 1;
979 }
980 auto j = nlohmann::json::parse(json);
981 serial::update_target_from_json(j, tgt, *ctx->getWorld(), ctx->getMasterSeeder());
982 return 0;
983 }
984 catch (const std::exception& e)
985 {
986 handle_api_exception(e, "fers_update_target_from_json");
987 return 1;
988 }
989}
void update_target_from_json(const nlohmann::json &j, radar::Target *existing_tgt, core::World &world, std::mt19937 &)
Updates a target from JSON without full context recreation.

References core::World::findTarget(), FersContext::getWorld(), handle_api_exception(), last_error_message, and serial::update_target_from_json().

+ Here is the call graph for this function:

◆ fers_update_timing_from_json()

int fers_update_timing_from_json ( fers_context_t context,
uint64_t  id,
const char json 
)

Updates a single timing source from JSON without full context recreation.

Parameters
contextA valid fers_context_t handle.
idThe unique ID of the timing source.
jsonThe JSON string for the timing source.
Returns
0 on success, non-zero on failure.

Definition at line 1021 of file api.cpp.

1022{
1023 last_error_message.clear();
1024 if ((context == nullptr) || (json == nullptr))
1025 return -1;
1026 auto* ctx = context;
1027 try
1028 {
1029 if (ctx->getWorld()->findTiming(id) == nullptr)
1030 {
1031 last_error_message = "Timing not found";
1032 return 1;
1033 }
1034 auto j = nlohmann::json::parse(json);
1035 serial::update_timing_from_json(j, *ctx->getWorld(), id);
1036 return 0;
1037 }
1038 catch (const std::exception& e)
1039 {
1040 handle_api_exception(e, "fers_update_timing_from_json");
1041 return 1;
1042 }
1043}
void update_timing_from_json(const nlohmann::json &j, core::World &world, const SimId id)
Updates a timing source from JSON without full context recreation.

References handle_api_exception(), last_error_message, and serial::update_timing_from_json().

+ Here is the call graph for this function:

◆ fers_update_transmitter_from_json()

int fers_update_transmitter_from_json ( fers_context_t context,
uint64_t  id,
const char json 
)

Updates a single transmitter from JSON without full context recreation.

Parameters
contextA valid fers_context_t handle.
idThe unique ID of the transmitter.
jsonThe JSON string for the transmitter.
Returns
0 on success, non-zero on failure.

Definition at line 916 of file api.cpp.

917{
918 last_error_message.clear();
919 if ((context == nullptr) || (json == nullptr))
920 return -1;
921 auto* ctx = context;
922 try
923 {
924 auto* tx = ctx->getWorld()->findTransmitter(id);
925 if (tx == nullptr)
926 {
927 last_error_message = "Transmitter not found";
928 return 1;
929 }
930 auto j = nlohmann::json::parse(json);
931 serial::update_transmitter_from_json(j, tx, *ctx->getWorld(), ctx->getMasterSeeder());
932 return 0;
933 }
934 catch (const std::exception& e)
935 {
936 handle_api_exception(e, "fers_update_transmitter_from_json");
937 return 1;
938 }
939}
void update_transmitter_from_json(const nlohmann::json &j, radar::Transmitter *tx, core::World &world, std::mt19937 &)
Updates a transmitter from JSON without full context recreation.

References core::World::findTransmitter(), FersContext::getWorld(), handle_api_exception(), last_error_message, and serial::update_transmitter_from_json().

+ Here is the call graph for this function:

◆ fers_update_waveform_from_json()

int fers_update_waveform_from_json ( fers_context_t context,
const char json 
)

Updates a single waveform from JSON without full context recreation.

Parameters
contextA valid fers_context_t handle.
jsonThe JSON string for the waveform.
Returns
0 on success, non-zero on failure.

Definition at line 893 of file api.cpp.

894{
895 last_error_message.clear();
896 if ((context == nullptr) || (json == nullptr))
897 return -1;
898 auto* ctx = context;
899 try
900 {
901 auto j = nlohmann::json::parse(json);
903 if (wf)
904 {
905 ctx->getWorld()->replace(std::move(wf));
906 }
907 return 0;
908 }
909 catch (const std::exception& e)
910 {
911 handle_api_exception(e, "fers_update_waveform_from_json");
912 return 1;
913 }
914}
std::unique_ptr< fers_signal::RadarSignal > parse_waveform_from_json(const nlohmann::json &j)
Parses a Waveform from JSON.

References handle_api_exception(), last_error_message, and serial::parse_waveform_from_json().

+ Here is the call graph for this function:

◆ fers_use_hdf5_output()

int fers_use_hdf5_output ( fers_context_t context)

Resets the context output mode to the default HDF5 output.

Runtime-only VITA 49.2 endpoint settings are retained for later VITA runs, but the selected output mode is changed back to HDF5.

Parameters
contextA valid fers_context_t handle.
Returns
0 on success, non-zero on error.

Definition at line 440 of file api.cpp.

441{
442 last_error_message.clear();
443 if (context == nullptr)
444 {
445 set_api_error("Invalid arguments: context is NULL.");
446 return -1;
447 }
448
449 auto* ctx = context;
450 try
451 {
452 core::OutputConfig config = ctx->getOutputConfig();
454 ctx->setOutputConfig(std::move(config));
455 return 0;
456 }
457 catch (const std::exception& e)
458 {
459 handle_api_exception(e, "fers_use_hdf5_output");
460 return 1;
461 }
462}

References handle_api_exception(), core::Hdf5, last_error_message, and core::OutputConfig::mode.

+ Here is the call graph for this function:

◆ handle_api_exception()

static void handle_api_exception ( const std::exception &  e,
const std::string function_name 
)
static

Centralized exception handler for the C-API boundary.

This function catches standard C++ exceptions, records their what() message into the thread-local error storage, and logs the error. This prevents C++ exceptions from propagating across the FFI boundary, which would be undefined behavior.

Parameters
eThe exception that was caught.
function_nameThe name of the API function where the error occurred.

Definition at line 72 of file api.cpp.

73{
74 last_error_message = e.what();
75 LOG(logging::Level::ERROR, "API Error in {}: {}", function_name, last_error_message);
76}

References logging::ERROR, last_error_message, and LOG.

Referenced by fers_calculate_preview_links(), fers_configure_logging(), fers_context_create(), fers_enable_vita49_udp_output(), fers_generate_kml(), fers_get_antenna_pattern(), fers_get_interpolated_motion_path(), fers_get_interpolated_rotation_path(), fers_get_last_output_metadata_json(), fers_get_memory_projection_json(), fers_get_scenario_as_json(), fers_get_scenario_as_xml(), fers_load_scenario_from_xml_file(), fers_load_scenario_from_xml_string(), fers_set_output_directory(), fers_set_thread_count(), fers_update_antenna_from_json(), fers_update_monostatic_from_json(), fers_update_parameters_from_json(), fers_update_platform_from_json(), fers_update_receiver_from_json(), fers_update_scenario_from_json(), fers_update_target_from_json(), fers_update_timing_from_json(), fers_update_transmitter_from_json(), fers_update_waveform_from_json(), and fers_use_hdf5_output().

+ Here is the caller graph for this function:

◆ map_api_log_level()

static logging::Level map_api_log_level ( fers_log_level_t  level)
static

Definition at line 129 of file api.cpp.

130{
131 switch (level)
132 {
133 case FERS_LOG_TRACE:
135 case FERS_LOG_DEBUG:
137 case FERS_LOG_INFO:
139 case FERS_LOG_WARNING:
141 case FERS_LOG_ERROR:
143 case FERS_LOG_FATAL:
145 case FERS_LOG_OFF:
146 return logging::Level::OFF;
147 default:
149 }
150}
@ FERS_LOG_FATAL
Fatal logging for unrecoverable failures.
Definition api.h:199
@ FERS_LOG_DEBUG
Debug-level diagnostic logging.
Definition api.h:195
@ FERS_LOG_ERROR
Error logging for failed operations.
Definition api.h:198
@ FERS_LOG_OFF
Disables logging output.
Definition api.h:200
@ FERS_LOG_INFO
Informational logging.
Definition api.h:196
@ FERS_LOG_TRACE
Trace-level diagnostic logging.
Definition api.h:194
@ FERS_LOG_WARNING
Warning logging for recoverable issues.
Definition api.h:197
@ WARNING
Warning level for potentially harmful situations.
@ FATAL
Fatal level for severe error events.
@ TRACE
Trace level for detailed debugging information.
@ OFF
Special level to disable all logging.
@ DEBUG
Debug level for general debugging information.

References logging::DEBUG, logging::ERROR, logging::FATAL, FERS_LOG_DEBUG, FERS_LOG_ERROR, FERS_LOG_FATAL, FERS_LOG_INFO, FERS_LOG_OFF, FERS_LOG_TRACE, FERS_LOG_WARNING, logging::INFO, logging::OFF, logging::TRACE, and logging::WARNING.

Referenced by fers_configure_logging(), and fers_log().

+ Here is the caller graph for this function:

◆ map_internal_log_level()

static fers_log_level_t map_internal_log_level ( logging::Level  level)
static

Definition at line 152 of file api.cpp.

153{
154 switch (level)
155 {
157 return FERS_LOG_TRACE;
159 return FERS_LOG_DEBUG;
161 return FERS_LOG_INFO;
163 return FERS_LOG_WARNING;
165 return FERS_LOG_ERROR;
167 return FERS_LOG_FATAL;
169 return FERS_LOG_OFF;
170 default:
171 return FERS_LOG_INFO;
172 }
173}

References logging::DEBUG, logging::ERROR, logging::FATAL, FERS_LOG_DEBUG, FERS_LOG_ERROR, FERS_LOG_FATAL, FERS_LOG_INFO, FERS_LOG_OFF, FERS_LOG_TRACE, FERS_LOG_WARNING, logging::INFO, logging::OFF, logging::TRACE, and logging::WARNING.

Referenced by fers_get_log_level().

+ Here is the caller graph for this function:

◆ to_cpp_interp_type()

math::Path::InterpType to_cpp_interp_type ( const fers_interp_type_t  type)

Definition at line 1273 of file api.cpp.

1274{
1275 switch (type)
1276 {
1277 case FERS_INTERP_LINEAR:
1279 case FERS_INTERP_CUBIC:
1281 case FERS_INTERP_STATIC:
1282 default:
1284 }
1285}
@ FERS_INTERP_STATIC
Definition api.h:596
@ FERS_INTERP_LINEAR
Definition api.h:597
@ INTERP_STATIC
Hold the first coordinate for all query times.
@ INTERP_LINEAR
Linearly interpolate between neighboring coordinates.
@ INTERP_CUBIC
Cubically interpolate between neighboring coordinates.

References FERS_INTERP_CUBIC, FERS_INTERP_LINEAR, FERS_INTERP_STATIC, math::Path::INTERP_CUBIC, math::Path::INTERP_LINEAR, and math::Path::INTERP_STATIC.

Referenced by fers_get_interpolated_motion_path().

+ Here is the caller graph for this function:

◆ to_cpp_rot_interp_type()

math::RotationPath::InterpType to_cpp_rot_interp_type ( const fers_interp_type_t  type)

Definition at line 1287 of file api.cpp.

1288{
1289 switch (type)
1290 {
1291 case FERS_INTERP_LINEAR:
1293 case FERS_INTERP_CUBIC:
1295 case FERS_INTERP_STATIC:
1296 default:
1298 }
1299}
@ INTERP_STATIC
Hold the first rotation for all query times.
@ INTERP_LINEAR
Linearly interpolate between neighboring rotations.
@ INTERP_CUBIC
Cubically interpolate between neighboring rotations.

References FERS_INTERP_CUBIC, FERS_INTERP_LINEAR, FERS_INTERP_STATIC, math::RotationPath::INTERP_CUBIC, math::RotationPath::INTERP_LINEAR, and math::RotationPath::INTERP_STATIC.

Referenced by fers_get_interpolated_rotation_path().

+ Here is the caller graph for this function:

Variable Documentation

◆ last_error_message

◆ last_warning_messages