The RMP Motion Controller APIs
SampleAppsConsole.cpp
1#include <iostream>
2#include <sstream>
3#include <vector>
4#include <string>
5#include <map>
6#include <algorithm>
7
8#include "HelperFunctionsCpp.h"
9
10// Include the sample apps
11#include "SampleApps.h"
12
13using namespace RSI::RapidCode;
14
15constexpr int MAX_NUM_ARGS = 256;
16
17// Status flags
18bool noInput = false;
19bool quit = false;
20int exitCode = 0;
21
22// Map the sample app names to their corresponding sample app
23static std::map<std::string, std::shared_ptr<SampleApp>> SampleAppNamesMap =
24{
25 {"hardware-limits", std::make_shared<HardwareLimits>()},
26 {"memory", std::make_shared<Memory>()},
27 {"motion-hold-released-by-software-address", std::make_shared<MotionHoldReleasedBySoftwareAddress>()},
28 {"multiaxis-motion", std::make_shared<MultiaxisMotion>()},
29 {"path-motion", std::make_shared<PathMotion>()},
30 {"pvt-motion-multiaxis", std::make_shared<PVTmotionMultiAxis>()},
31 {"single-axis-sync-outputs", std::make_shared<SingleAxisSyncOutputs>()},
32 {"sync-output-with-motion", std::make_shared<SyncOutputWithMotion>()},
33 {"update-buffer-points", std::make_shared<UpdateBufferPoints>()},
34 {"user-limit-digital-input-action", std::make_shared<UserLimitDigialInputAction>()}
35};
36
37// Print the list of available sample apps
38static void ListSampleApps()
39{
40 std::cout << std::endl << "Available Sample Apps:" << std::endl;
41
42 // Iterate over the sample app names and print them
43 std::shared_ptr<SampleApp> sampleApp;
44 for (auto const& sampleAppName : SampleAppNamesMap)
45 {
46 std::cout << " - " << sampleAppName.first << std::endl;
47 }
48}
49
50// Print the information on running with hardware
51static void PrintHardwareHelp()
52{
53 std::cout << std::endl << "To run a SampleApp with hardware you must complete the following steps:" << std::endl;
54 std::cout << " 1. In the source file for the SampleApp, set the axis configuration parameters." << std::endl;
55 std::cout << " 2. Still in the source file, set the 'USE_HARDWARE' flag to true in the class's run method." << std::endl;
56 std::cout << " 3. Rebuild this project." << std::endl;
57 std::cout << " 4. Ensure that you have taken all proper safety precautions appropriate to your particular hardware setup." << std::endl;
58 std::cout << " 5. Relaunch 'SampleAppsCPP.exe' and run the SampleApp to observe the results." << std::endl;
59}
60
61// Print the help message
62static void PrintHelp()
63{
64 std::cout << std::endl << "Enter the name of a Sample App to run it." << std::endl;
65 std::cout << " - Running on hardware requires additional configuration. Type 'hardware' for more information." << std::endl;
66 std::cout << std::endl << "You may also use 'runall' to run all supported Sample Apps." << std::endl;
67 std::cout << std::endl << "Type 'l' or 'list' to list the available Sample Apps." << std::endl;
68}
69
70static void PrintWelcomeMessage()
71{
72 std::cout << "Welcome to the RapidCode C++ Sample Apps!" << std::endl << std::endl;
73 std::cout << "This program allows you to run the sample apps that are included with the RapidCode API." << std::endl;
74 std::cout << std::endl << "WARNING: The sample apps are meant to be used as a reference and may not contain all of the logic and safety features that your application requires." << std::endl;
75 std::cout << "Additionally, in order to mitigate unexpected behavior, running a sample app will reset your RMP controller, clearing any previous configuration." << std::endl;
76 std::cout << std::endl << "It is recommended that you do not have any hardware connected when running the sample apps for the first time." << std::endl;
77 std::cout << "Before you attempt to run a sample app with hardware, please ensure that you have completed the necessary configuration steps and reviewed the source files." << std::endl;
78 std::cout << "Type 'hardware' for more information." << std::endl;
79 ListSampleApps();
80}
81
82// Get the sample app using the string name
83static std::shared_ptr<SampleApp> GetSampleApp(std::string sampleAppName)
84{
85 // Convert the input to lowercase
86 std::transform(sampleAppName.begin(), sampleAppName.end(), sampleAppName.begin(),
87 [](unsigned char c) { return std::tolower(c); });
88
89 // Check if the input is a valid sample app name
90 if (SampleAppNamesMap.find(sampleAppName) == SampleAppNamesMap.end())
91 {
92 throw std::invalid_argument("Error: Invalid Sample App name.");
93 }
94
95 // Get the sample app
96 return SampleAppNamesMap.at(sampleAppName);
97}
98
99// Run the sample app
100static int RunSampleApp(std::string sampleAppName)
101{
102 // Initialize the exit code
103 int appExitCode = 0;
104
105 // Try find the specified sample app
106 std::shared_ptr<SampleApp> sampleApp;
107 try
108 {
109 sampleApp = GetSampleApp(sampleAppName);
110 }
111 catch (std::invalid_argument& e)
112 {
113 std::cout << std::endl << e.what() << std::endl;
114 ListSampleApps();
115 return -1;
116 }
117
118 // Run the requested sample app
119 std::cout << std::endl << "--------------------------------------------------" << std::endl;
120 std::cout << "Running " << sampleAppName << "..." << std::endl;
121 std::cout << "--------------------------------------------------" << std::endl << std::endl;
122 try
123 {
124 appExitCode = sampleApp->Run();
125 }
126 catch (std::exception& e)
127 {
128 std::cout << std::endl << "Error: " << e.what() << std::endl;
129 appExitCode = -2;
130 }
131
132 std::cout << std::endl << "--------------------------------------------------" << std::endl;
133
134 // Print the result of the sample app
135 if (appExitCode == 0)
136 {
137 std::cout << "Sample App " << sampleAppName << " completed successfully." << std::endl;
138 }
139 else
140 {
141 std::cout << "Sample App " << sampleAppName << " completed with errors." << std::endl;
142 }
143
144 std::cout << "--------------------------------------------------" << std::endl << std::endl;
145
146 return appExitCode;
147}
148
149// Run all the sample apps that are set to run that are configured for the specified hardware mode
150static int RunAll()
151{
152 int runallExitCode = 0;
153 int appExitCode = 0;
154 std::vector<std::string> failedSampleApps;
155 for (auto const& sampleAppName : SampleAppNamesMap)
156 {
157 appExitCode = RunSampleApp(sampleAppName.first);
158
159 // Record the apps that failed
160 if (appExitCode != 0)
161 {
162 failedSampleApps.push_back(sampleAppName.first);
163 }
164
165 // Lower exit codes are more severe, so we want to keep the lowest exit code
166 if (appExitCode < runallExitCode)
167 {
168 runallExitCode = appExitCode;
169 }
170 }
171
172 // Print the list of failed sample apps
173 if (failedSampleApps.size() > 0)
174 {
175 std::cout << std::endl << "The following Sample Apps failed:" << std::endl;
176 for (auto const& sampleAppName : failedSampleApps)
177 {
178 std::cout << " - " << sampleAppName << std::endl;
179 }
180 }
181
182 return runallExitCode;
183}
184
185// Get the arguments from the user
186static std::vector<std::string> GetInput()
187{
188 std::string input;
189 std::cout << std::endl << "Enter a Sample App name or 'runall'. Type 'h' or 'help' for more info. Type 'q' or 'quit' to end program." << std::endl;
190 std::cout << std::endl << ">> ";
191 std::getline(std::cin, input);
192
193 std::istringstream streamInput(input);
194 std::string token;
195 std::vector<std::string> args;
196 while (std::getline(streamInput, token, ' '))
197 {
198 args.push_back(token);
199 }
200
201 return args;
202}
203
204static int ProcessInput(std::vector<std::string> args)
205{
206 // If no arguments are provided print the help message
207 if (args.size() < 1 ||
208 args[0] == "h" ||
209 args[0] == "help")
210 {
211 PrintHelp();
212 return 0;
213 }
214
215 // If the first argument is 'hardware', print the hardware information
216 if (args[0] == "hardware")
217 {
218 PrintHardwareHelp();
219 return 0;
220 }
221
222 // If the first argument is 'list', list the available sample apps
223 if (args[0] == "l" || args[0] == "list")
224 {
225 ListSampleApps();
226 return 0;
227 }
228
229 // If the first argument is 'q' or 'quit', end the program
230 if (args[0] == "q" || args[0] == "quit")
231 {
232 quit = true;
233 return 0;
234 }
235
236 // If the first argument is 'runall', check if the second argument is 'phantoms' or 'hardware'
237 if (args[0] == "runall")
238 {
239 return RunAll();
240 }
241
242 // Try to run the specified sample app
243 return RunSampleApp(args[0]);
244}
245
246// Parse the command line arguements
247std::vector<std::string> ParseArgs(int argc, char* argv[])
248{
249 std::vector<std::string> args;
250 std::string arg;
251 for (int i = 1; i < argc; i++)
252 {
253 arg = argv[i]; // Convert the char* to a string
254 // Check for special arguments which all start with "--"
255 if (arg == "--no-input")
256 {
257 noInput = true;
258 }
259 else // All other arguments are added to the args vector
260 {
261 args.push_back(arg);
262 }
263 }
264
265 return args;
266}
267
268int main(int argc, char* argv[])
269{
270 // Check for too many arguments
271 if (argc > MAX_NUM_ARGS)
272 {
273 std::cout << "Error: Too many arguments." << std::endl;
274 return -1;
275 }
276
277 // Parse the command line arguments
278 std::vector<std::string> args;
279 if (argc > 1)
280 {
281 args = ParseArgs(argc, argv);
282 exitCode = ProcessInput(args);
283 }
284
285 // If the --no-input flag is set, then exit the program after processing the command line arguments
286 if (noInput)
287 {
288 return exitCode;
289 }
290
291 // Print the welcome message
292 PrintWelcomeMessage();
293
294 // Get the input from the user and process it until they quit
295 while (!quit)
296 {
297 args = GetInput();
298 exitCode = ProcessInput(args);
299 }
300
301 return exitCode;
302}