FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2025-present FERS Contributors (see AUTHORS.md).
3
4/**
5 * @file main.cpp
6 * @brief Entry point for the FERS command-line interface (CLI).
7 *
8 * This executable acts as a wrapper around the libfers core library. It parses
9 * command-line arguments, uses the libfers C-API to load and run a simulation,
10 * and reports progress to the console.
11 */
12
13#include <filesystem>
14#include <format>
15#include <fstream>
16#include <iostream>
17#include <libfers/api.h>
18#include <string>
19
20#include "arg_parser.h"
21#include "cli_paths.h"
22
23// --- Shim to restore LOG() functionality via C-API ---
24namespace logging
25{
26 static inline std::string getLevelString(fers_log_level_t l)
27 {
28 switch (l)
29 {
30 case FERS_LOG_TRACE:
31 return "TRACE";
32 case FERS_LOG_DEBUG:
33 return "DEBUG";
34 case FERS_LOG_INFO:
35 return "INFO";
37 return "WARNING";
38 case FERS_LOG_ERROR:
39 return "ERROR";
40 case FERS_LOG_FATAL:
41 return "FATAL";
42 default:
43 return "UNKNOWN";
44 }
45 }
46}
47
48// Define LOG macro to format arguments and pass them to the library's logger
49#define LOG(level, ...) \
50 do \
51 { \
52 std::string _msg = std::format(__VA_ARGS__); \
53 fers_log(level, _msg.c_str()); \
54 } \
55 while (0)
56// -----------------------------------------------------
57
58int main(const int argc, char* argv[])
59{
60 // Parse command-line arguments using the local arg parser
61 const auto config_result = core::parseArguments(argc, argv);
62 if (!config_result)
63 {
64 if (config_result.error() != "Help requested." && config_result.error() != "Version requested." &&
65 config_result.error() != "No arguments provided.")
66 {
67 // Use basic stderr here because logging isn't configured yet
68 std::cerr << "[ERROR] Argument parsing error: " << config_result.error() << '\n';
69 return 1;
70 }
71 return 0;
72 }
73
74 const auto& [script_file, log_level, num_threads, validate, log_file, generate_kml, kml_file, output_dir] =
75 config_result.value();
76
77 // Configure logging via the C API
78 const char* log_file_ptr = log_file ? log_file->c_str() : nullptr;
79 if (fers_configure_logging(log_level, log_file_ptr) != 0)
80 {
81 // If we can't configure logging, we must print to stderr manually
82 char* err = fers_get_last_error_message();
83 std::cerr << "[ERROR] Failed to configure logging: " << ((err != nullptr) ? err : "Unknown error") << '\n';
85 return 1;
86 }
87
88 LOG(FERS_LOG_INFO, "FERS CLI started. Using libfers backend.");
89
91 "Running FERS with arguments: script_file={}, log_level={}, num_threads={}, validate={}, log_file={}",
92 script_file, logging::getLevelString(log_level), num_threads, validate, log_file.value_or("None"));
93
94 const std::filesystem::path final_out_dir = core::resolveOutputDir(script_file, output_dir);
95
96 // Create a simulation context using the C-API
98 if (context == nullptr)
99 {
100 LOG(FERS_LOG_FATAL, "Failed to create FERS simulation context.");
101 return 1;
102 }
103
104 // Set the output directory via the C-API
105 if (fers_set_output_directory(context, final_out_dir.string().c_str()) != 0)
106 {
107 char* err = fers_get_last_error_message();
108 LOG(FERS_LOG_FATAL, "Failed to set output directory: {}", err ? err : "Unknown error");
109 fers_free_string(err);
110 fers_context_destroy(context);
111 return 1;
112 }
113
114 // Load the scenario from file via the C-API
115 LOG(FERS_LOG_INFO, "Loading scenario from '{}'...", script_file);
116 if (fers_load_scenario_from_xml_file(context, script_file.c_str(), validate ? 1 : 0) != 0)
117 {
118 char* err = fers_get_last_error_message();
119 LOG(FERS_LOG_FATAL, "Failed to load scenario: {}", err ? err : "Unknown error");
120 fers_free_string(err);
121 fers_context_destroy(context);
122 return 1;
123 }
124
125 if (generate_kml)
126 {
127 const std::filesystem::path kml_output_path = core::resolveKmlOutputPath(script_file, final_out_dir, kml_file);
128 const std::string kml_output_file = kml_output_path.string();
129
130 LOG(FERS_LOG_INFO, "Generating KML file for scenario: {}", kml_output_file);
131 if (fers_generate_kml(context, kml_output_file.c_str()) == 0)
132 {
133 LOG(FERS_LOG_INFO, "KML file generated successfully: {}", kml_output_file);
134 }
135 else
136 {
137 char* err = fers_get_last_error_message();
138 LOG(FERS_LOG_FATAL, "Failed to generate KML file: {}", err ? err : "Unknown error");
139 fers_free_string(err);
140 }
141
142 fers_context_destroy(context);
143 return 0; // Exit after generating KML
144 }
145
146 // Set thread count via the C-API
147 if (fers_set_thread_count(num_threads) != 0)
148 {
149 char* err = fers_get_last_error_message();
150 LOG(FERS_LOG_ERROR, "Failed to set number of threads: {}", err ? err : "Unknown error");
151 fers_free_string(err);
152 }
153
154 // Run the simulation via the C-API
155 LOG(FERS_LOG_INFO, "Starting simulation...");
156 if (fers_run_simulation(context, nullptr, nullptr) != 0)
157 {
158 char* err = fers_get_last_error_message();
159 LOG(FERS_LOG_FATAL, "Simulation run failed: {}", err ? err : "Unknown error");
160 fers_free_string(err);
161 fers_context_destroy(context);
162 return 1;
163 }
164 LOG(FERS_LOG_INFO, "Simulation completed successfully.");
165
166 fers_context_destroy(context);
167
168 return 0;
169}
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.
Definition api.cpp:274
char * fers_get_last_error_message()
Retrieves the last error message that occurred on the current thread.
Definition api.cpp:728
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.
Definition api.cpp:798
fers_log_level_t
Log levels for the FERS library.
Definition api.h:86
@ FERS_LOG_FATAL
Definition api.h:92
@ FERS_LOG_DEBUG
Definition api.h:88
@ FERS_LOG_ERROR
Definition api.h:91
@ FERS_LOG_INFO
Definition api.h:89
@ FERS_LOG_TRACE
Definition api.h:87
@ FERS_LOG_WARNING
Definition api.h:90
int fers_set_output_directory(fers_context_t *context, const char *out_dir)
Sets the output directory for simulation results.
Definition api.cpp:252
void fers_context_destroy(fers_context_t *context)
Destroys a FERS simulation context and releases all associated memory.
Definition api.cpp:108
fers_context_t * fers_context_create()
Creates a new FERS simulation context.
Definition api.cpp:88
int fers_run_simulation(fers_context_t *context, fers_progress_callback_t callback, void *user_data)
Runs the simulation defined in the provided context.
Definition api.cpp:760
void fers_free_string(char *str)
Frees a string that was allocated and returned by the libfers API.
Definition api.cpp:752
int fers_configure_logging(fers_log_level_t level, const char *log_file_path)
Configures the internal logger.
Definition api.cpp:188
int fers_set_thread_count(unsigned num_threads)
Sets the number of worker threads for the simulation.
Definition api.cpp:233
Command-line argument parsing utilities for the application.
int main(const int argc, char *argv[])
Definition main.cpp:58
#define LOG(level,...)
Definition main.cpp:49
std::filesystem::path resolveKmlOutputPath(const std::string &script_file, const std::filesystem::path &final_output_dir, const std::optional< std::string > &kml_file) noexcept
Definition cli_paths.cpp:25
std::filesystem::path resolveOutputDir(const std::string &script_file, const std::optional< std::string > &output_dir) noexcept
Definition cli_paths.cpp:8
std::expected< Config, std::string > parseArguments(const int argc, char *argv[]) noexcept
Parses command-line arguments.
std::string getLevelString(const Level level) noexcept
Converts a log level enum value to its string representation.
Definition logging.h:143