diff options
author | FormerLurker <hochgebe@gmail.com> | 2020-05-13 19:07:49 +0300 |
---|---|---|
committer | FormerLurker <hochgebe@gmail.com> | 2020-05-13 19:07:49 +0300 |
commit | 7afcf6e187fa30f28dfc647616e21156528a1cb7 (patch) | |
tree | 692f9370ed1a70f775ef8444a66af707e58ff6fc /ArcWelderConsole | |
parent | a0edbce74133753543903a03c3c2df19964ff2c9 (diff) |
Enhance Argument Parsing for Console App with TCLAP.
Diffstat (limited to 'ArcWelderConsole')
-rw-r--r-- | ArcWelderConsole/ArcWelderConsole.cpp | 321 | ||||
-rw-r--r-- | ArcWelderConsole/ArcWelderConsole.h | 2 | ||||
-rw-r--r-- | ArcWelderConsole/ArcWelderConsole.vcxproj | 11 | ||||
-rw-r--r-- | ArcWelderConsole/CMakeLists.txt | 5 | ||||
-rw-r--r-- | ArcWelderConsole/Makefile | 5 |
5 files changed, 137 insertions, 207 deletions
diff --git a/ArcWelderConsole/ArcWelderConsole.cpp b/ArcWelderConsole/ArcWelderConsole.cpp index 7286ae9..4495dfa 100644 --- a/ArcWelderConsole/ArcWelderConsole.cpp +++ b/ArcWelderConsole/ArcWelderConsole.cpp @@ -28,206 +28,135 @@ #include <sstream> #include <iomanip> #include "gcode_position.h" +#include <tclap/CmdLine.h> + int main(int argc, char* argv[]) { - std::string info = "Arc Welder: Anti-Stutter v0.1.rc1.dev0\nReduces the number of gcodes per second sent to a 3D printer that supports arc commands (G2 G3)\nCopyright(C) 2020 - Brad Hochgesang\n"; - std::cout << info; - // General Strings - std::string usage_string = "Usage: "; - std::string default_value_string = "Default Value: "; - std::string usage_example_string = "Example Usage: "; - // Resolution messages - std::string resolution_parameter = "--resolution-mm"; - std::string resolution_usage = resolution_parameter + " {float}"; - std::string resolution_description = "The resolution in mm of the of the output. Determines the maximum tool path deviation allowed during conversion."; - std::string resolution_default_value = "0.05 (in millimeters)"; - std::string resolution_usage_example = resolution_parameter + " 0.1"; - // g90/g91 influences extruder messages - std::string g90_influences_extruder_parameter = "--g90-influences-extruder"; - std::string g90_influences_extruder_usage = g90_influences_extruder_parameter + " {true/false}"; - std::string g90_influences_extruder_description = "If true, G90 and G91 influence the E axis. This can affect retraction and extrusion calculations depending on the gcode."; - std::string g90_influences_extruder_default_value = "false"; - std::string g90_influences_extruder_usage_example = g90_influences_extruder_parameter + " true"; - // show_progress messages - std::string show_progress_parameter = "--show-progress"; - std::string show_progress_usage = show_progress_parameter + " {true/false}"; - std::string show_progress_description = "Display a periodic progress message every 1 second."; - std::string show_progress_default_value = "true"; - std::string show_progress_usage_example = show_progress_parameter + " false"; - // log level messages - std::string log_level_parameter = "--log-level"; - std::string log_level_usage = log_level_parameter + " {NOSET/VERBOSE/DEBUG/INFO/WARNING/ERROR/CRITICAL}"; - std::string log_level_usage_description = "Sets console log level. DEBUG, VERBOSE, AND NOSET will produce a HUGE amount of output, and will slow processing considerably. Errors and Exceptions will be logged to stderr."; - std::string log_level_usage_default_value = "ERROR"; - std::string log_level_usage_example = log_level_parameter + " DEBUG"; - - std::stringstream usage_message_stream; - usage_message_stream << usage_string << argv[0] << " {SOURCE_PATH} {DESTINATION_PATH} {optional arguments}\n"; - usage_message_stream << usage_example_string << argv[0] << "\"c:\\source_file.gcode\" \"c:\\target_file.gcode\" -resolution 0.05 -g90-91-influences-extruder false -log-level DEBUG\n"; - usage_message_stream << "********************\n"; - usage_message_stream << "Argument Description:\n"; - usage_message_stream << "SOURCE_PATH:\n\tThe full path of the gcode file to compress. This is a required argument\n"; - usage_message_stream << "TARGET_PATH:\n\tThe full path of the compressed gcode output. Any existing target file will be overwritten!\n"; - usage_message_stream << resolution_usage << "\n\t" << resolution_description << "\n\t" << default_value_string << resolution_default_value << "\n\t" << usage_example_string << resolution_usage_example << "\n"; - usage_message_stream << g90_influences_extruder_usage << "\n\t" << g90_influences_extruder_description << "\n\t" << default_value_string << g90_influences_extruder_default_value << "\n\t" << usage_example_string << g90_influences_extruder_usage_example << "\n"; - usage_message_stream << show_progress_parameter << "\n\t" << show_progress_description << "\n\t" << default_value_string << show_progress_default_value << "\n\t" << usage_example_string << show_progress_usage_example << "\n"; - usage_message_stream << log_level_usage << "\n\t" << log_level_usage_description << "\n\t" << default_value_string << log_level_usage_default_value << "\n\t" << usage_example_string << log_level_usage_example << "\n"; - - // Ensure at least 3 parameters, including the cmd. - if (argc < 3) - { - if (argc > 1) - std::cerr << "Error executing " << argv[0] << ": Invalid number of arguments.\n"; - else - std::cout << argv[0] << " - Displaying Help\n"; - std::cout << usage_message_stream.str(); - if (argc > 1) - return 1; - return -1; - } - // get the source and target path - std::string source_file_path = argv[1]; - std::string target_file_apth = argv[2]; - double resolution_mm = 0.05; - bool g90_g91_influences_extruder = false; - bool show_progress = true; - int log_level_value = 40; - // Extract opotional parameters - std::vector <std::string> sources; - for (int i = 3; i < argc; ++i) { - std::string parameter; - for (unsigned int letter_index = 0; letter_index < strlen(argv[i]); letter_index++) - parameter += tolower(argv[i][letter_index]); - - if (parameter == resolution_parameter) { - // make sure we have another argument after the flag - if (i + 1 >= argc) - { - std::cerr << "The " << resolution_parameter <<" parameter requires a float value.\n\t" << usage_string << resolution_usage << "\n\t" << usage_example_string << resolution_usage_example << "\n"; - return 1; - } - i++; // increment the index to extract the parameter's value - try - { - resolution_mm = std::stod(argv[i]); - } - catch (std::invalid_argument) { - std::cerr << "Unable to convert the " << resolution_parameter << " value '" << argv[i] << "' to a float.\n\t" << usage_string << resolution_usage << "\n\t" << usage_example_string << resolution_usage_example << "\n"; - return 1; - } - } - else if (parameter == g90_influences_extruder_parameter) - { - // make sure we have another argument after the flag - if (i + 1 >= argc) - { - std::cerr << "The " << g90_influences_extruder_parameter << " parameter requires a boolean value.\n\t" << usage_string << g90_influences_extruder_usage << "\n\t" << usage_example_string << g90_influences_extruder_usage_example << "\n"; - return 1; - } - i++; // increment the index to extract the parameter's value - std::string g90_g91_influences_extruder_string; - - for (unsigned int letter_index = 0; letter_index < strlen(argv[i]); letter_index++) - g90_g91_influences_extruder_string += toupper(argv[i][letter_index]); - - if (g90_g91_influences_extruder_string != "TRUE" && g90_g91_influences_extruder_string != "FALSE") - { - std::cerr << "Unable to convert the " << g90_influences_extruder_parameter << " value '" << argv[i] << "' to a boolean.\n\t" << usage_string << g90_influences_extruder_usage << "\n\t" << usage_example_string << g90_influences_extruder_usage_example << "\n"; - return 1; - } - g90_g91_influences_extruder = g90_g91_influences_extruder_string == "TRUE"; - } - else if (parameter == show_progress_parameter) - { - // make sure we have another argument after the flag - if (i + 1 >= argc) - { - std::cerr << "The " << show_progress_parameter << " parameter requires a boolean value.\n\t" << usage_string << show_progress_usage << "\n\t" << usage_example_string << show_progress_usage_example << "\n"; - return 1; - } - i++; // increment the index to extract the parameter's value - std::string show_progress_string; - for (unsigned int letter_index = 0; letter_index < strlen(argv[i]); letter_index++) - show_progress_string += toupper(argv[i][letter_index]); - if (show_progress_string != "TRUE" && show_progress_string != "FALSE") - { - std::cerr << "Unable to convert the " << show_progress_parameter << " value '" << argv[i] << "' to a boolean.\n\t" << usage_string << show_progress_usage << "\n\t" << usage_example_string << show_progress_usage_example << "\n"; - return 1; - } - show_progress = show_progress_string == "TRUE"; - } - else if (parameter == log_level_parameter) - { - // make sure we have another argument after the flag - if (i + 1 >= argc) - { - std::cerr << "The " << log_level_parameter << " parameter requires a valid log level string.\n\t" << usage_string << log_level_usage << "\n\t" << usage_example_string << log_level_usage_example << "\n"; - return 1; - } - i++; // increment the index to extract the parameter's value - std::string log_level_name; - for (unsigned int letter_index = 0; letter_index < strlen(argv[i]); letter_index++) - log_level_name += toupper(argv[i][letter_index]); - - // Ensure the log level name is valid - log_level_value = -1; - for (unsigned int log_name_index = 0; log_name_index < log_level_names.size(); log_name_index++) - { - if (log_level_name == log_level_names[log_name_index]) - { - log_level_value = log_level_values[log_name_index]; - break; - } - } - if (log_level_value == -1) - { - std::cerr << "Unable to convert the " << log_level_parameter << " value '" << argv[i] << "' to a valid log level string.\n\t" << usage_string << log_level_usage << "\n\t" << usage_example_string << log_level_usage_example << "\n"; - return 1; - } - - } - else { - std::cerr << "An unknown parameter '" << parameter << "' was received.\n" << usage_message_stream.str(); - return 1; - } - } - - std::vector<std::string> log_names; - log_names.push_back("arc_welder.gcode_conversion"); - std::vector<int> log_levels; - log_levels.push_back(log_levels::DEBUG); - logger* p_logger = new logger(log_names, log_levels); - p_logger->set_log_level_by_value(log_level_value); - std::string log_level_name = "No Logging"; - if (log_level_value >= 0) log_level_names[logger::get_log_level_for_value(log_level_value)]; - - std::stringstream log_messages; - log_messages << "Processing Gcode\n"; - log_messages << "\tSource File Path : " << source_file_path << "\n"; - log_messages << "\tTarget File File : " << target_file_apth << "\n"; - log_messages << "\tResolution in MM : " << resolution_mm << "\n"; - log_messages << "\tG90/G91 Influences Extruder : " << (g90_g91_influences_extruder ? "True" : "False") << "\n"; - log_messages << "\tLog Level : " << log_level_name << "\n"; - log_messages << "\tShow Progress Updates : " << (show_progress ? "True" : "False") << "\n"; - std::cout << log_messages.str(); - arc_welder* p_arc_welder = NULL; - if (show_progress) - p_arc_welder = new arc_welder(source_file_path, target_file_apth, p_logger, resolution_mm, g90_g91_influences_extruder, 50, on_progress); - else - p_arc_welder = new arc_welder(source_file_path, target_file_apth, p_logger, resolution_mm, g90_g91_influences_extruder, 50); - - p_arc_welder->process(); - - delete p_arc_welder; - log_messages.clear(); - log_messages.str(""); - log_messages << "Target file at '" << target_file_apth << "' created. Exiting."; - p_logger->log(0, INFO, log_messages.str()); - return 0; + std::string source_file_path; + std::string target_file_path; + double resolution_mm; + bool g90_g91_influences_extruder; + bool hide_progress; + std::string log_level_string; + int log_level_value; + std::string version = "0.1.0"; + std::string info = "Arc Welder: Anti-Stutter - Reduces the number of gcodes per second sent to a 3D printer that supports arc commands (G2 G3)\nCopyright(C) 2020 - Brad Hochgesang"; + + // Extract arguments + try { + // Define the command line object + TCLAP::CmdLine cmd(info, '=', version); + + // Define Arguments + + // <SOURCE> + TCLAP::UnlabeledValueArg<std::string> source_arg("source", "The source gcode file to convert.", true, "", "path to source gcode file"); + + // <TARGET> + TCLAP::UnlabeledValueArg<std::string> target_arg("target", "The target gcode file containing the converted code.", true, "", "path to target gcode file"); + + // -r --resolution-mm + TCLAP::ValueArg<float> resolution_arg("r", "resolution-mm", "The resolution in mm of the of the output. Determines the maximum tool path deviation allowed during conversion.", false, 0.05f, "float"); + + // -g --g90-influences-extruder + TCLAP::SwitchArg g90_arg("g", "g90-influences-extruder", "If supplied, G90/G91 influences the extruder axis.", false); + + // -g --hide-progress + TCLAP::SwitchArg hide_progress_arg("p", "hide-progress", "If supplied, prevents progress updates from being displayed.", false); + + // -l --log-level + std::vector<std::string> log_levels_vector; + log_levels_vector.push_back("NOSET"); + log_levels_vector.push_back("VERBOSE"); + log_levels_vector.push_back("DEBUG"); + log_levels_vector.push_back("INFO"); + log_levels_vector.push_back("WARNING"); + log_levels_vector.push_back("ERROR"); + log_levels_vector.push_back("CRITICAL"); + log_levels_vector.push_back(""); + TCLAP::ValuesConstraint<std::string> log_levels_constraint(log_levels_vector); + TCLAP::ValueArg<std::string> log_level_arg("l", "log-level", "Sets console log level.", false, "ERROR", &log_levels_constraint); + + // Add all arguments + cmd.add(source_arg); + cmd.add(target_arg); + cmd.add(resolution_arg); + cmd.add(g90_arg); + cmd.add(hide_progress_arg); + cmd.add(log_level_arg); + + // Parse the argv array. + cmd.parse(argc, argv); + + // Get the value parsed by each arg. + source_file_path = source_arg.getValue(); + target_file_path = target_arg.getValue(); + resolution_mm = resolution_arg.getValue(); + g90_g91_influences_extruder = g90_arg.getValue(); + hide_progress = hide_progress_arg.getValue(); + log_level_string = log_level_arg.getValue(); + + log_level_value = -1; + for (unsigned int log_name_index = 0; log_name_index < log_level_names.size(); log_name_index++) + { + if (log_level_string == log_level_names[log_name_index]) + { + log_level_value = log_level_values[log_name_index]; + break; + } + } + if (log_level_value == -1) + { + // TODO: Does this work? + throw new TCLAP::ArgException("Unknown log level"); + } + + } + // catch argument exceptions + catch (TCLAP::ArgException& e) + { + std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; + return 1; + } + + // Ensure the log level name is valid + + std::vector<std::string> log_names; + log_names.push_back("arc_welder.gcode_conversion"); + std::vector<int> log_levels; + log_levels.push_back(log_levels::DEBUG); + logger* p_logger = new logger(log_names, log_levels); + p_logger->set_log_level_by_value(log_level_value); + + std::stringstream log_messages; + log_messages << "Processing Gcode\n"; + log_messages << "\tSource File Path : " << source_file_path << "\n"; + log_messages << "\tTarget File File : " << target_file_path << "\n"; + log_messages << "\tResolution in MM : " << resolution_mm << "\n"; + log_messages << "\tG90/G91 Influences Extruder : " << (g90_g91_influences_extruder ? "True" : "False") << "\n"; + log_messages << "\tLog Level : " << log_level_string << "\n"; + log_messages << "\tHide Progress Updates : " << (hide_progress ? "True" : "False") << "\n"; + std::cout << log_messages.str(); + arc_welder* p_arc_welder = NULL; + if (!hide_progress) + p_arc_welder = new arc_welder(source_file_path, target_file_path, p_logger, resolution_mm, g90_g91_influences_extruder, 50, on_progress); + else + p_arc_welder = new arc_welder(source_file_path, target_file_path, p_logger, resolution_mm, g90_g91_influences_extruder, 50); + + p_arc_welder->process(); + + delete p_arc_welder; + log_messages.clear(); + log_messages.str(""); + log_messages << "Target file at '" << target_file_path << "' created. Exiting."; + p_logger->log(0, INFO, log_messages.str()); + + return 0; } static bool on_progress(arc_welder_progress progress) { - std::cout << progress.str() << "\n"; - return true; + std::cout << progress.str() << "\n"; + return true; } + diff --git a/ArcWelderConsole/ArcWelderConsole.h b/ArcWelderConsole/ArcWelderConsole.h index d7ac5b9..9a6199e 100644 --- a/ArcWelderConsole/ArcWelderConsole.h +++ b/ArcWelderConsole/ArcWelderConsole.h @@ -24,4 +24,4 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma once #include "arc_welder.h" -static bool on_progress(arc_welder_progress progress);
\ No newline at end of file +static bool on_progress(arc_welder_progress progress); diff --git a/ArcWelderConsole/ArcWelderConsole.vcxproj b/ArcWelderConsole/ArcWelderConsole.vcxproj index 06b6e76..620980d 100644 --- a/ArcWelderConsole/ArcWelderConsole.vcxproj +++ b/ArcWelderConsole/ArcWelderConsole.vcxproj @@ -71,19 +71,19 @@ <PropertyGroup Label="UserMacros" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <LinkIncremental>true</LinkIncremental> - <IncludePath>$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath> + <IncludePath>$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)\TCLAP\</IncludePath> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <LinkIncremental>true</LinkIncremental> - <IncludePath>$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath> + <IncludePath>$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)\TCLAP\</IncludePath> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <LinkIncremental>false</LinkIncremental> - <IncludePath>$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath> + <IncludePath>$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)\TCLAP\</IncludePath> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <LinkIncremental>false</LinkIncremental> - <IncludePath>$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath> + <IncludePath>$(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)\TCLAP\</IncludePath> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> @@ -154,6 +154,9 @@ <ProjectReference Include="..\GcodeProcessorLib\GcodeProcessorLib.vcxproj"> <Project>{31478bae-104b-4cc3-9876-42fa90cbd5fe}</Project> </ProjectReference> + <ProjectReference Include="..\TCLAP\TCLAP.vcxproj"> + <Project>{38302600-81a7-45bb-a199-3360d6594365}</Project> + </ProjectReference> </ItemGroup> <ItemGroup> <Text Include="CMakeLists.txt" /> diff --git a/ArcWelderConsole/CMakeLists.txt b/ArcWelderConsole/CMakeLists.txt index e197aac..bbc9302 100644 --- a/ArcWelderConsole/CMakeLists.txt +++ b/ArcWelderConsole/CMakeLists.txt @@ -18,4 +18,7 @@ add_executable(${PROJECT_NAME} ${ArcWelderConsoleSources}) install(TARGETS ${PROJECT_NAME}) # specify linking to the GcodeProcessorLib and ArcWelder libraries -target_link_libraries(${PROJECT_NAME} GcodeProcessorLib ArcWelder) +target_link_libraries(${PROJECT_NAME} GcodeProcessorLib ArcWelder TCLAP) + + + diff --git a/ArcWelderConsole/Makefile b/ArcWelderConsole/Makefile deleted file mode 100644 index 3291fe0..0000000 --- a/ArcWelderConsole/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -all: - g++ -o ArcWelderConsole -I../GcodeProcessorLib -I../ArcWelder ../GcodeProcessorLib/*.o ../ArcWelder/*.o ArcWelderConsole.cpp - -clean: - rm -f ArcWelderConsole |