OTX-Runtime for C++  
Runtime API Sample Program

The Sample program demonstrates the main functionality of the OTX-Runtime API. It can be used as a reference for the expected runtime behavior of the API and the source code below is like a reference guide about the proper programming of the API.

Code Example CPP-File

Code example (.\otxruntime\Sample.Console\src\Main.cpp) of the OTX-Runtime API Sample Program.

1 #include <iostream>
2 #include <memory>
3 #include <thread>
4 #include <string>
5 #include <sstream>
6 #include <regex>
7 
8 /* Header files of the OTX-Runtime-Api */
9 #include <RuntimeManagerFactory.h>
10 #include <IRuntimeContext.h>
11 #include <RuntimeConfig.h>
12 #include <Project/IProject.h>
13 #include <Otx/IPackage.h>
14 #include <Otx/IDocument.h>
15 #include <Otx/IContextVariable.h>
16 #include <Otx/IStateVariable.h>
17 #include <Otx/IProcedure.h>
18 #include <Otx/IProcedureParameter.h>
19 #include <Otx/IProcedureInParameter.h>
20 #include <Otx/IProcedureInOutParameter.h>
21 #include <DataTypes/Object.h>
22 #include <DataTypes/ValueConverter.h>
23 #include <Exceptions/Exception.h>
24 
25 using namespace OpenTestSystem::Otx::Runtime::Api;
26 
27 #include <SingletonManager.h>
28 using OpenTestSystem::Otx::Common::SingletonManager;
29 
30 #include <License/LicenseManager.h>
32 /***************************************/
33 
34 /* Header files of the DiagManager */
35 #include <IOtxDiag.h>
36 #include <IDiagConfiguration.h>
37 #include <OtxDiagFactory.h>
38 using namespace OpenTestSystem::Otx::DiagManager::OtxDiagApi;
39 
40 #include <CommandProcessor.h>
41 using OpenTestSystem::Otx::DiagManager::CommandProcessor::CommandProcessor;
42 
43 #ifdef _WIN32
44 #include <filesystem.h>
45 namespace fs = otx::filesystem;
46 
47 HMODULE DiagRuntimeSystemDLL = NULL;
48 std::string GetLastErrorAsString();
49 #elif defined(__linux__) || defined(__QNXNTO__)
50 #include <unistd.h>
51 #include <sys/types.h>
52 #include <dirent.h>
53 #include <signal.h>
54 #ifdef USE_VWMCD_LINK_LIBRARY
55 #ifdef USE_VWMCDSP
56 #include <VwMcdSPDiagRuntimeSystem.h>
57 typedef OpenTestSystem::Otx::DiagManager::DiagRuntimeSystem::VwMcdSPDiagRuntimeSystem VwMcdDiagRuntimeSystem;
58 #else
59 #include <VwMcdDiagRuntimeSystem.h>
60 typedef OpenTestSystem::Otx::DiagManager::DiagRuntimeSystem::VwMcdDiagRuntimeSystem VwMcdDiagRuntimeSystem;
61 #endif
62 #else
63 #include <dlfcn.h>
64 void* handle;
65 #endif // USE_VWMCD_LINK_LIBRARY
66 #endif
67 using OpenTestSystem::Otx::DiagManager::Common::IDiagRuntimeSystem;
68 
69 #include "../../../lib/OpenTestSystem.OtxDiagManager.SystemApi/include/Util.h"
70 using OpenTestSystem::Otx::DiagManager::SystemApi::Util;
71 /***************************************/
72 
73 /* Header files of the CustomImplementations */
74 #include <DefaultMeasureImplementation.h>
75 #include <StateVariableImplementation.h>
76 #include <ContextVariableImplementation.h>
77 #include <DefaultCustomScreenImplementation.h>
78 #include <DefaultExternalServiceProviderImplementation.h>
80 /***************************************/
81 
82 #include "ExecutionState.h"
83 #include <ClientFactory.h>
84 
85 bool isProcedureFinished = false;
86 CommandProcessor* cp = nullptr;
87 std::shared_ptr<IRuntimeManager> runtimeManager;
88 std::vector<std::shared_ptr<Otx::IProcedure>> DisplayPtxTree(std::shared_ptr<Project::IProject> project);
89 std::shared_ptr<Otx::IProcedure> GetProcedure(std::shared_ptr<Project::IProject> project, std::string procedureFullName);
90 void SelectAndExecuteProcedure(std::shared_ptr<IRuntimeManager> runtimeManager, std::shared_ptr<Project::IProject> project, std::vector<std::shared_ptr<Otx::IProcedure>> procedures);
91 std::string SelectProject(std::shared_ptr<IDiagConfiguration> diagConfiguration);
92 std::string SelectVehicleInformation(std::shared_ptr<IDiagConfiguration> diagConfiguration);
93 std::shared_ptr<IOtxDiag> CreateRawOtxDiag();
94 
95 std::string licenseKey;
96 bool IsLicenseValid(std::string);
97 void ReadAndSetOtxRuntimeLicense();
98 
99 IDiagRuntimeSystem* CreateDiagRuntimeSystem(const char* projectName, const char* vehicleInfo, const char* kernelPath, bool useVwmcdSP);
100 
101 std::shared_ptr<DefaultCustomScreenImplementation> customScreenImplementation = std::make_shared<DefaultCustomScreenImplementation>();
102 std::shared_ptr<DefaultMeasureImplementation> measureImplementation = std::make_shared<DefaultMeasureImplementation>();
103 std::shared_ptr<StateVariableImplementation> stateVariableImplementation = std::make_shared<StateVariableImplementation>();
104 std::shared_ptr<ContextVariableImplementation> contextVariableImplementation = std::make_shared<ContextVariableImplementation>();
105 std::shared_ptr<DefaultExternalServiceProviderImplementation> externalServiceProviderImplementation = std::make_shared<DefaultExternalServiceProviderImplementation>();
106 
107 void ProcedureStarted(const IRuntimeContext& context)
108 {
109  std::cout << std::endl << "Procedure '" << context.GetProcedure()->GetFullName() << "' started" << std::endl;
110 }
111 
112 void ProcedureFinished(const IRuntimeContext& context)
113 {
114  std::cout << std::endl << "Procedure '" << context.GetProcedure()->GetFullName() << "' finished" << std::endl;
115 
116  for (size_t i = 0; i < context.GetProcedure()->GetParameters().size(); i++)
117  {
118  std::shared_ptr<Otx::IProcedureParameter> procedureParameter = context.GetProcedure()->GetParameters().at(i);
119 
120  std::cout << std::endl << "\tParameterValueFinished(" << procedureParameter->GetDataType() << ", " << procedureParameter->GetName() << " = " << procedureParameter->GetValue()->ToLiteralString() << ")";
121  }
122  std::cout << std::endl;
123 
124  isProcedureFinished = true;
125 }
126 
127 void ProcedureAborted(const IRuntimeContext& context)
128 {
129  std::cout << std::endl << "Procedure '" << context.GetProcedure()->GetFullName() << "' aborted" << std::endl;
130  isProcedureFinished = true;
131 }
132 
133 void ProcedureStopped(const IRuntimeContext& context)
134 {
135  std::cout << std::endl << "Procedure '" << context.GetProcedure()->GetFullName() << "' stopped" << std::endl;
136 
137  isProcedureFinished = true;
138 }
139 
140 
141 void ProcedureTimeout(const IRuntimeContext& context)
142 {
143  std::cout << std::endl << "Procedure '" << context.GetProcedure()->GetFullName() << "' timeout expired" << std::endl;
144 }
145 
146 void InOutParameterValueChanged(const IRuntimeContext& context, const IProcedureInOutParameter& parameter)
147 {
148  std::string separator = " || ";
149  time_t now = time(0);
150  tm* ltm = localtime(&now);
151  std::stringstream ss;
152  ss << ltm->tm_hour << ":" << ltm->tm_min << ":" << ltm->tm_sec;
153 
154  std::string outputLog = "InOutParameterValueChanged(" + parameter.GetDataType() + ", " + parameter.GetName() + " = " + parameter.GetValue()->ToLiteralString() + ")";
155 
156  std::cout << "\t" << ss.str() << separator << outputLog << std::endl;
157 }
158 
159 void ContextVariableRead(std::shared_ptr<IContextVariable> contextVariable, std::shared_ptr<Object> value)
160 {
161  std::string separator = " || ";
162  time_t now = time(0);
163  tm* ltm = localtime(&now);
164  std::stringstream ss;
165  ss << ltm->tm_hour << ":" << ltm->tm_min << ":" << ltm->tm_sec;
166 
167  std::string mappingStr = contextVariable->GetMappingName().empty() ? "" : (" [MappedTo: " + contextVariable->GetMappingName() + (contextVariable->GetMappingIndex() > -1 ? ("[" + std::to_string(contextVariable->GetMappingIndex()) + "]") : "") + "]");
168  std::string outputLog = "ContextVariableRead(" + contextVariable->GetDataType() + ", " + contextVariable->GetDocument()->GetFullName() + "." + contextVariable->GetName() + mappingStr + " = " + value->ToLiteralString() + ")";
169 
170  std::cout << "\t" << ss.str() << separator << outputLog << std::endl;
171 }
172 void StateVariableValueChanged(std::shared_ptr<IStateVariable> stateVariable, std::shared_ptr<Object> value)
173 {
174  std::string mappingStr = stateVariable->GetMappingName().empty() ? "" : (" [MappedTo: " + stateVariable->GetMappingName() + (stateVariable->GetMappingIndex() > -1 ? ("[" + std::to_string(stateVariable->GetMappingIndex()) + "]") : "") + "]");
175  std::string outputLog = "StateVariableChanged(" + stateVariable->GetDataType() + ", " + stateVariable->GetDocument()->GetFullName() + "." + stateVariable->GetName() + mappingStr + " = " + value->ToLiteralString() + ")";
176  std::string separator = " || ";
177  time_t now = time(0);
178  tm* ltm = localtime(&now);
179  std::stringstream ss;
180  ss << ltm->tm_hour << ":" << ltm->tm_min << ":" << ltm->tm_sec;
181 
182  std::cout << "\t" << ss.str() << separator << outputLog << std::endl;
183 }
184 
185 std::vector<std::string> SplitString(std::string str, char delimiter)
186 {
187  std::string token;
188  std::istringstream ss(str);
189  std::vector<std::string> tokens;
190  while (std::getline(ss, token, delimiter))
191  {
192  tokens.push_back(token);
193  }
194 
195 
196  return tokens;
197 }
198 
199 bool IsLicenseValid(std::string licenseKey)
200 {
201  try
202  {
203  LicenseManager::SetLicenseKey(licenseKey);
204  // Try to create a runtime manager instance with the inputed license key. An exception is thrown if the license key is invalid.
206  return true;
207  }
208  catch (const std::exception& e)
209  {
210  std::cout << e.what() << std::endl;
211  return false;
212  }
213 }
214 
215 void ReadAndSetOtxRuntimeLicense()
216 {
217  while (true)
218  {
219  std::cout << "Please enter your OtxRuntime license key here (enter empty to exit): ";
220  std::getline(std::cin, licenseKey);
221 
222  if (licenseKey.empty())
223  {
224  exit(0);
225  }
226 
227  std::regex pattern("^[0-9a-zA-Z]{5}-[0-9a-zA-Z]{5}-[0-9a-zA-Z]{5}-[0-9a-zA-Z]{5}-[0-9a-zA-Z]{5}$|^$");
228 
229  if (std::regex_match(licenseKey, pattern)) // license key must match the format XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
230  {
231  if (!IsLicenseValid(licenseKey))
232  {
233  continue;
234  }
235  else
236  {
237  break;
238  }
239  }
240  else
241  {
242  std::cout << "License key does not match the desired format XXXXX-XXXXX-XXXXX-XXXXX-XXXXX. Enter empty to exit.\n";
243  }
244  }
245 }
246 
247 int main(int argc, char** argv)
248 {
249  ReadAndSetOtxRuntimeLicense();
250 
251  std::string runtimeManagerType;
252 
253  while (true)
254  {
255  std::cout << "Select a RuntimeManager:" << std::endl << "\t1 or empty - Raw." << std::endl << "\t2 - Socket." << std::endl << "\t3 - Pipe." << std::endl;
256  std::cout << "Enter a number: ";
257  std::getline(std::cin, runtimeManagerType);
258  if (runtimeManagerType == "" || runtimeManagerType == "1")
259  {
260  std::shared_ptr<IOtxDiag> otxDiag = nullptr;
261  try
262  {
263  otxDiag = CreateRawOtxDiag(); // Create a Raw DiagManager instance
264  if (!otxDiag)
265  {
266  return EXIT_FAILURE;
267  }
268 
269  runtimeManager = RuntimeManagerFactory::CreateRawRuntimeManager(otxDiag); // Create a Raw RuntimeManager with the Raw DiagManager instance above
270  std::cout << "\tRawRuntimeManager is created." << std::endl;
271  std::shared_ptr<IDiagConfiguration> diagConfiguration = otxDiag->GetDiagConfiguration();
272  std::string projectName, vehicleInformationName;
273  projectName = SelectProject(diagConfiguration); // Select an available ODX-Runtime-Project
274  if (!projectName.empty())
275  {
276  vehicleInformationName = SelectVehicleInformation(diagConfiguration); // Select an available vehicle information
277  }
278  }
279  catch (const std::exception& ex)
280  {
281  std::cerr << ex.what() << std::endl;
282  continue;
283  }
284 
285  break;
286  }
287  else if (runtimeManagerType == "2")
288  {
289  int otxRunnerPort, diagManagerPort;
290  while (true)
291  {
292  std::cout << "Enter OtxRunnerPort and DiagManagerPort, separated by space: ";
293  std::string input;
294  std::getline(std::cin, input);
295  std::vector<std::string> tokens = SplitString(input, ' ');
296  try
297  {
298  otxRunnerPort = atoi(tokens.at(0).c_str());
299  diagManagerPort = atoi(tokens.at(1).c_str());
300  break;
301  }
302  catch (const std::exception& ex)
303  {
304  std::cerr << ex.what() << std::endl;
305  continue;
306  }
307 
308  std::cout << "Wrong numbers!" << std::endl;
309  }
310 
311  try
312  {
313  // Create a RuntimeManager socket on otxRunnerPort, which then works with an active diagManager at the provided port.
314  runtimeManager = RuntimeManagerFactory::CreateSocketRuntimeManager(otxRunnerPort, diagManagerPort);
315  }
316  catch (const std::exception& ex)
317  {
318  std::cerr << ex.what() << std::endl;
319  continue;
320  }
321 
322  std::cout << "\tSocketRuntimeManager(otxRunnerPort=" << otxRunnerPort << ", diagManagerPort=" << diagManagerPort << ") was created." << std::endl;
323  break;
324  }
325  else if (runtimeManagerType == "3")
326  {
327  std::string otxRunnerPipeName, diagManagerPipeName;
328  while (true)
329  {
330  std::cout << "Enter OtxRunnerPipeName and DiagManagerPipeName, separated by space: ";
331  std::string input;
332  std::getline(std::cin, input);
333  std::vector<std::string> tokens = SplitString(input, ' ');
334  try
335  {
336  otxRunnerPipeName = tokens.at(0);
337  diagManagerPipeName = tokens.at(1);
338  break;
339  }
340  catch (const std::exception& ex)
341  {
342  std::cerr << ex.what() << std::endl;
343  continue;
344  }
345 
346  std::cout << "Wrong names!" << std::endl;
347  }
348 
349  try
350  {
351  // Create a RuntimeManager pipe with given otxRunnerPipeName, which then works with an active diagManager via pipe at the provided pipe name.
352  runtimeManager = RuntimeManagerFactory::CreatePipeRuntimeManager(otxRunnerPipeName, diagManagerPipeName);
353  }
354  catch (const std::exception& ex)
355  {
356  std::cerr << ex.what() << std::endl;
357  continue;
358  }
359 
360  std::cout << "\tPipeRuntimeManager(otxRunnerPipeName=\"" << otxRunnerPipeName << "\", diagManagerPipeName=\"" << diagManagerPipeName << "\") was created." << std::endl;
361  break;
362  }
363 
364  std::cout << "Wrong number!" << std::endl;
365  }
366 
367  printf("\temotive OTX-Runtime API (Version %s - MinBin: %s)\n\n", RuntimeConfig::GetInstance().GetVersion().c_str(), RuntimeConfig::GetInstance().GetMinBinVersion().c_str());
368 
369  // Set the Custom implementations
370  runtimeManager->SetCustomImplementation(customScreenImplementation);
371  runtimeManager->SetCustomImplementation(measureImplementation);
372  runtimeManager->SetCustomImplementation(externalServiceProviderImplementation);
373  stateVariableImplementation->SetStateVariableValueChangedHandler(std::make_shared<std::function<void(std::shared_ptr<IStateVariable>, std::shared_ptr<Object>)>>(StateVariableValueChanged));
374  runtimeManager->SetCustomImplementation(stateVariableImplementation);
375  contextVariableImplementation->SetContextVariableReadHandler(std::make_shared<std::function<void(std::shared_ptr<IContextVariable>, std::shared_ptr<Object>)>>(ContextVariableRead));
376  runtimeManager->SetCustomImplementation(contextVariableImplementation);
377 
378  // Register the event handlers!!!
379  std::shared_ptr<std::function<void(const IRuntimeContext&)>> procedureStartListener = std::make_shared<std::function<void(const IRuntimeContext&)>>(ProcedureStarted);
380  std::shared_ptr<std::function<void(const IRuntimeContext&)>> procedureFinishedListener = std::make_shared<std::function<void(const IRuntimeContext&)>>(ProcedureFinished);
381  std::shared_ptr<std::function<void(const IRuntimeContext&)>> procedureAbortedListener = std::make_shared<std::function<void(const IRuntimeContext&)>>(ProcedureAborted);
382  std::shared_ptr<std::function<void(const IRuntimeContext&)>> procedureStoppedListener = std::make_shared<std::function<void(const IRuntimeContext&)>>(ProcedureStopped);
383  std::shared_ptr<std::function<void(const IRuntimeContext&, const IProcedureInOutParameter&)>> parameterChangedListener = std::make_shared<std::function<void(const IRuntimeContext&, const IProcedureInOutParameter&)>>(InOutParameterValueChanged);
384  std::shared_ptr<std::function<void(const IRuntimeContext&)>> procedureTimeoutListener = std::make_shared<std::function<void(const IRuntimeContext&)>>(ProcedureTimeout);
385 
386  runtimeManager->AddProcedureStartedListener(procedureStartListener);
387  runtimeManager->AddProcedureFinishedListener(procedureFinishedListener);
388  runtimeManager->AddProcedureTimeoutListener(procedureTimeoutListener);
389  runtimeManager->AddProcedureAbortedListener(procedureAbortedListener);
390  runtimeManager->AddProcedureStoppedListener(procedureStoppedListener);
391  runtimeManager->AddInOutParameterValueChangedListener(parameterChangedListener);
392 
393  std::shared_ptr<Project::IProject> project = nullptr;
394 
395  while (true)
396  {
397  std::cout << "Enter PTX: ";
398  std::string ptxFile;
399  std::getline(std::cin, ptxFile);
400  try
401  {
402  if (ptxFile.at(0) == '"' && ptxFile.at(ptxFile.size() - 1) == '"')
403  {
404  ptxFile = ptxFile.substr(1, ptxFile.size() - 2);
405  }
406 
407  project = runtimeManager->LoadPtx(ptxFile); // Loads the given PTX file.
408 
409  break;
410  }
411  catch (std::exception& ex)
412  {
413  std::cerr << "\t" << ex.what() << std::endl;
414  }
415  }
416 
417  if (project)
418  {
419  std::vector<std::shared_ptr<Otx::IProcedure>> procedures = DisplayPtxTree(project); // Display the PTX content
420 
421  // Execute a procedure with diagnostics(not the main)
422  SelectAndExecuteProcedure(runtimeManager, project, procedures);
423  }
424 
425  SingletonManager::Get().DestroyAll(); // Destroy all singletons in the runtime API to ensure a clean shutdown without warnings.
426 #ifdef _WIN32
427  system("pause");
428 #endif
429  delete cp;
430  return EXIT_SUCCESS;
431 }
432 
433 std::vector < std::shared_ptr<Otx::IProcedure>> DisplayPtxPackageTree(std::vector < std::shared_ptr<Otx::IProcedure>> procedures, std::vector < std::shared_ptr<Otx::IPackage>> packages, std::string stringConcat = "")
434 {
435  for (int i = 0; i < packages.size(); i++)
436  {
437  std::shared_ptr<Otx::IPackage> package = packages.at(i);
438  std::cout << stringConcat << " |- " << package->GetName() << " (Package)" << std::endl;
439 
440  procedures = DisplayPtxPackageTree(procedures, package->GetPackages(), stringConcat + " |");
441 
442  for (int j = 0; j < package->GetDocuments().size(); j++)
443  {
444  std::shared_ptr<Otx::IDocument> document = package->GetDocuments().at(j);
445  document->GetImports();
446 
447  std::cout << stringConcat << " | |- " << document->GetName() << " (Document)" << std::endl;
448  for (int k = 0; k < document->GetProcedures().size(); k++)
449  {
450  std::shared_ptr<Otx::IProcedure> procedure = document->GetProcedures().at(k);
451  procedures.push_back(procedure);
452  std::cout << stringConcat << " | | |- " << procedure->GetName() << " (Procedure)" << " - code: " << procedures.size() << std::endl;
453 
454  for (int m = 0; m < procedure->GetParameters().size(); m++)
455  {
456  std::shared_ptr<Otx::IProcedureParameter> param = procedure->GetParameters().at(m);
457 
458  std::string name = param->GetName();
459  std::string dataType = param->GetDataType();
460 
461  auto value = param->GetInitValue();
462  std::string valueStr = (value != nullptr ? value->ToLiteralString() : "null");
463 
464  if (std::shared_ptr<Otx::IProcedureInParameter> inParameter = std::dynamic_pointer_cast<Otx::IProcedureInParameter>(param))
465  {
466  std::cout <<
467  stringConcat << " | | | |- " << name << " (" << dataType << "): " << valueStr << " (InParameter or InOutParameter)" << std::endl;
468  }
469  else
470  {
471  std::cout << stringConcat << " | | | |- " << name << " (" << dataType << "): " << valueStr << " (OutParameter)" << std::endl;
472  }
473  }
474  }
475  }
476  }
477  return procedures;
478 }
479 
480 std::vector < std::shared_ptr<Otx::IProcedure>> DisplayPtxTree(std::shared_ptr<Project::IProject> project)
481 {
482  std::vector < std::shared_ptr<Otx::IProcedure>> procedures;
483  if (project != NULL)
484  {
485  std::cout << std::endl << "PTX tree: " << std::endl;
486 
487  std::cout << "- " << project->GetName() << " (Project)" << std::endl;
488 
489  procedures = DisplayPtxPackageTree(procedures, project->GetPackages());
490  }
491  return procedures;
492 }
493 
494 void SelectAndExecuteProcedure(std::shared_ptr<IRuntimeManager> runtimeManager, std::shared_ptr<Project::IProject> project, std::vector<std::shared_ptr<Otx::IProcedure>> procedures)
495 {
496 
497 ReEnterProcedure:
498  std::string procedureFullName;
499  std::cout << std::endl << "Enter Procedure (full name, code or 0 - if exit): ";
500  std::getline(std::cin, procedureFullName);
501 
502  std::shared_ptr<Otx::IProcedure> procedure = nullptr;
503  try
504  {
505  int idxProcedure = std::stoi(procedureFullName.c_str());
506  if (idxProcedure < 0 || idxProcedure>procedures.size() + 1)
507  {
508  std::cout << std::endl << "The procedure code is invalid.";
509  goto ReEnterProcedure;
510  }
511  else if (idxProcedure == 0 && procedureFullName.size() > 0)
512  {
513  return;
514  }
515  else
516  {
517  procedure = procedures.at(idxProcedure - 1); // Select the procedure to execute
518  }
519  }
520  catch (const std::exception&)
521  {
522 
523  }
524 
525  if (procedure != nullptr)
526  {
527  // Set value to procedure parameters
528  for (int i = 0; i < procedure->GetParameters().size(); i++)
529  {
530  std::shared_ptr<Otx::IProcedureParameter> procedureParameter = procedure->GetParameters().at(i);
531  if (std::shared_ptr<Otx::IProcedureInParameter> inParameter = std::dynamic_pointer_cast<Otx::IProcedureInParameter>(procedureParameter))
532  {
533  bool isValidValue = false;
534  do
535  {
536  try
537  {
538  isValidValue = true;
539  std::string value;
540  std::cout << "Enter value of " << procedureParameter->GetName() << " (" << procedureParameter->GetDataType() << "): ";
541  std::getline(std::cin, value);
542  if (value != "")
543  {
544  inParameter->SetValue(ValueConverter::String2Value(value, procedureParameter->GetDataType()));
545  }
546  }
547  catch (std::exception& ex)
548  {
549  isValidValue = false;
550  std::cerr << ex.what() << std::endl;
551  }
552  } while (!isValidValue);
553  }
554  else if (std::shared_ptr<Otx::IProcedureInOutParameter> inOutParameter = std::dynamic_pointer_cast<Otx::IProcedureInOutParameter>(procedureParameter))
555  {
556  bool isValidValue = false;
557  do
558  {
559  try
560  {
561  isValidValue = true;
562  std::string value;
563  std::cout << "Enter value of " << procedureParameter->GetName() << " (" << procedureParameter->GetDataType() << "): ";
564  std::getline(std::cin, value);
565  if (value != "")
566  {
567  inOutParameter->SetValue(ValueConverter::String2Value(value, procedureParameter->GetDataType()));
568  }
569  }
570  catch (std::exception& ex)
571  {
572  isValidValue = false;
573  std::cerr << ex.what() << std::endl;
574  }
575  } while (!isValidValue);
576  }
577  }
578 
579  isProcedureFinished = false;
580  std::shared_ptr<IRuntimeContext> runtimeContext = runtimeManager->ExecuteAsync(procedure); // Execute the selected procedure
581 
582  while (isProcedureFinished == false) // Poll and wait until the procedure finishes.
583  {
584  std::this_thread::sleep_for(std::chrono::milliseconds(1));
585  }
586 
587  if (runtimeContext->HasOtxException()) // Gets the uncatched otx exceptions from the procedure (ablauf) if any
588  {
589  std::cout << std::endl << "Otx exception occurred:" << "\t";
590  std::cout << runtimeContext->GetOtxException().GetOtxType() << ":" << runtimeContext->GetOtxException().what() << std::endl;
591  }
592  else if (runtimeContext->HasRuntimeException()) // Gets the uncatched runtime exceptions in the execution if any
593  {
594  std::cout << std::endl << "Runtime exception occurred:" << "\t";
595  std::cout << runtimeContext->GetRuntimeException().what() << std::endl;
596  }
597  }
598  else
599  {
600  std::cout << "Procedure " << procedureFullName << " does not exist!" << std::endl;
601  }
602 
603  goto ReEnterProcedure;
604 }
605 
606 std::string SelectProject(std::shared_ptr<IDiagConfiguration> diagConfiguration)
607 {
608  std::string projectSelected;
609  int indexProjectSelect = 0;
610 
611  std::shared_ptr<IDiagConfiguration> diagConfig = diagConfiguration;
612  if (diagConfig == NULL)
613  {
614  diagConfig = CreateRawOtxDiag()->GetDiagConfiguration();
615  }
616  std::vector<std::string> projectList = diagConfig->GetDbProjectList(); // Get all available ODX projects for selecting
617 
618  if (projectList.size() > 0)
619  {
620  std::cout << "Select a ODX-Runtime-Project" << std::endl;
621  std::cout << "\t0 - None" << std::endl;
622 
623  for (size_t indexProjectItem = 0; indexProjectItem < projectList.size(); indexProjectItem++)
624  {
625  std::cout << "\t" << indexProjectItem + 1 << " - " << projectList.at(indexProjectItem) << std::endl;
626  }
627 
628 #ifdef _WIN32
629  flushall();
630 #endif
631  std::cout << "Enter a number: ";
632  std::cin >> indexProjectSelect;
633  std::cin.ignore();
634  if (indexProjectSelect > 0 && indexProjectSelect - 1 < projectList.size())
635  {
636  projectSelected = projectList.at(indexProjectSelect - 1);
637  diagConfig->SelectProject(projectSelected);
638  }
639  }
640 
641  return projectSelected;
642 }
643 
644 std::string SelectVehicleInformation(std::shared_ptr<IDiagConfiguration> diagConfiguration)
645 {
646  std::string vehicleSelected;
647  int indexVehicleInformationSelect = 0;
648 
649  std::shared_ptr<IDiagConfiguration> _diagConfiguration = diagConfiguration;
650  if (_diagConfiguration == NULL)
651  {
652  _diagConfiguration = CreateRawOtxDiag()->GetDiagConfiguration();
653  }
654  std::vector<std::string> vehicleInformationList = _diagConfiguration->GetDbVehicleInformationList();
655 
656  for (size_t indexVehicleInformationName = 0; indexVehicleInformationName < vehicleInformationList.size(); indexVehicleInformationName++)
657  {
658  std::cout << "\t" << indexVehicleInformationName + 1 << " - " << vehicleInformationList.at(indexVehicleInformationName) << std::endl;
659  }
660 
661 #ifdef _WIN32
662  flushall();
663 #endif
664  std::cout << "Input vehicle information code: ";
665  std::cin >> indexVehicleInformationSelect;
666  std::cin.ignore();
667  if (indexVehicleInformationSelect > 0 && indexVehicleInformationSelect - 1 < vehicleInformationList.size())
668  {
669  vehicleSelected = vehicleInformationList.at(indexVehicleInformationSelect - 1);
670  _diagConfiguration->SelectVehicleInformation(vehicleSelected);
671  }
672  return vehicleSelected;
673 }
674 
675 std::shared_ptr<IOtxDiag> CreateRawOtxDiag()
676 {
677  OpenTestSystem::Otx::DiagManager::OtxDiagApi::OtxDiagFactory factory;
678 
679  if (cp == nullptr)
680  {
681  cp = new CommandProcessor;
682  }
683 
684  bool useVwmcdSP = false;
685 #ifdef USE_VWMCDSP
686  useVwmcdSP = true;
687 #endif
688  OpenTestSystem::Otx::DiagManager::Client::ClientFactory clientFactory;
689  std::shared_ptr<OpenTestSystem::Otx::DiagManager::Client::Client> rawClient = clientFactory.CreateRawClient(cp);
690  Util::SetLicenseKey(rawClient, licenseKey); // use the license key of otx runtime also for diagmanager
691  const char* kernelPath = getenv("VW_MCD_HOME");
692  if (!kernelPath)
693  {
694  std::cout << "\tCannot read ENVIRONMENT VARIABLE 'VW_MCD_HOME'" << std::endl;
695  return nullptr;
696  }
697 
698  const char* configPath = getenv("VW_MCD_CONFIG");
699  if (!configPath)
700  {
701  std::cout << "\tCannot read ENVIRONMENT VARIABLE 'VW_MCD_CONFIG'" << std::endl;
702  return nullptr;
703  }
704 
705  std::cout << "\tVW_MCD_HOME = " << kernelPath << std::endl;
706  std::cout << "\tVW_MCD_CONFIG = " << configPath << std::endl;
707  IDiagRuntimeSystem* drs = CreateDiagRuntimeSystem("", "", kernelPath, useVwmcdSP);
708  if (drs == nullptr)
709  {
710  std::cout << "\tInitDiagRuntimeSystem failed!" << std::endl;
711  return nullptr;
712  }
713  cp->SetRuntimeSystem(drs);
714  return factory.CreateRawOtxDiag(cp);
715 }
716 #ifdef _WIN32
717 std::string GetLastErrorAsString()
718 {
719  //Get the error message ID, if any.
720  DWORD errorMessageID = ::GetLastError();
721  if (errorMessageID == 0) {
722  return std::string(); //No error message has been recorded
723  }
724 
725  LPSTR messageBuffer = nullptr;
726 
727  //Ask Win32 to give us the string version of that message ID.
728  //The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
729  size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
730  NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
731 
732  //Copy the error message into a std::string.
733  std::string message(messageBuffer, size);
734 
735  //Free the Win32's string's buffer.
736  LocalFree(messageBuffer);
737 
738  return message;
739 }
740 #endif
741 
742 IDiagRuntimeSystem* CreateDiagRuntimeSystem(const char* projectName, const char* vehicleInfo, const char* kernelPath, bool useVwmcdSP)
743 {
744 #ifdef _WIN32
745  typedef IDiagRuntimeSystem* (__cdecl* typeCreateDiagRuntimeSystem)(const char* projectName, const char* vehicleInfo);
746  DiagRuntimeSystemDLL = NULL;
747 
748  // represents vwmcd version 17.50.x.x
749  std::string DiagRuntimeSystem_17_50_FileName = "OpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.VwMcd_VC142.dll";
750  // represents vwmcdsp version 17.50.0.x.x
751  std::string DiagRuntimeSystemSP_17_50_FileName = "OpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.VwMcdSP_VC142.dll";
752  // represents vwmcd version 9.00.x.x to 14.00.x.x
753  std::string DiagRuntimeSystem_09_00_FileName = "OpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.dll";
754  // represents vwmcdsp version 9.00.x.x to 14.00.x.x
755  std::string DiagRuntimeSystemSP_09_00_FileName = "OpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.VwMcd90SP.dll";
756 
757  // Default use mcd version 17.50.x.x
758  std::string DiagRuntimeSystemFileName = DiagRuntimeSystem_17_50_FileName;
759  std::string kernelTypeStr = "VwMcd1750";
760 
761  if (useVwmcdSP)
762  {
763  kernelTypeStr = "VwMcd1750SP";
764  DiagRuntimeSystemFileName = DiagRuntimeSystemSP_17_50_FileName;
765  }
766 
767  if (fs::exists(std::string(kernelPath) + "/McdKernel_vc120.dll")) // check vwmcd 90
768  {
769  if (useVwmcdSP)
770  {
771  kernelTypeStr = "VwMcd90SP";
772  DiagRuntimeSystemFileName = DiagRuntimeSystemSP_09_00_FileName;
773  }
774  else
775  {
776  kernelTypeStr = "VwMcd90";
777  DiagRuntimeSystemFileName = DiagRuntimeSystem_09_00_FileName;
778  }
779  }
780 
781  std::cout << "\tKernel Type is " << kernelTypeStr << std::endl;
782 
783  DiagRuntimeSystemDLL = ::LoadLibrary(DiagRuntimeSystemFileName.c_str());
784  if (DiagRuntimeSystemDLL == NULL)
785  {
786  std::string errorMessage = GetLastErrorAsString();
787  std::cout << errorMessage << std::endl;
788  throw std::exception(errorMessage.c_str());
789  }
790 
791  typedef IDiagRuntimeSystem* (__cdecl* typeCreateDiagRuntimeSystem)(const char* projectName, const char* vehicleInfo);
792  typeCreateDiagRuntimeSystem createFunction = reinterpret_cast<typeCreateDiagRuntimeSystem>(::GetProcAddress(DiagRuntimeSystemDLL, "CreateDiagRuntimeSystem"));
793 
794  if (createFunction == nullptr)
795  return nullptr;
796 
797  return createFunction(projectName, vehicleInfo);
798 #elif defined(__linux__) || defined(__QNXNTO__)
799 #ifdef USE_VWMCD_LINK_LIBRARY
800  return new VwMcdDiagRuntimeSystem(projectName, vehicleInfo);
801 #else
802  if (!handle && useVwmcdSP == false)
803  {
804  std::cout << "Kernel Type is VwMcd" << std::endl;
805  handle = dlopen("libOpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.VwMcd.so", RTLD_NOW);
806  }
807  else if (!handle && useVwmcdSP == true)
808  {
809  std::cout << "Kernel Type is VwMcdSP" << std::endl;
810  handle = dlopen("libOpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.VwMcdSP.so", RTLD_NOW);
811  }
812 
813  if (!handle) {
814  /* fail to load the library */
815  std::cout << dlerror() << std::endl;
816  return nullptr;
817  }
818  typedef IDiagRuntimeSystem* typeCreateDiagRuntimeSystem(const char* projectName, const char* vehicleInfo);
819  typeCreateDiagRuntimeSystem* createFunction = reinterpret_cast<typeCreateDiagRuntimeSystem*>(dlsym(handle, "CreateDiagRuntimeSystem"));
820 
821  if (!createFunction)
822  {
823  dlclose(handle);
824  return nullptr;
825  }
826  IDiagRuntimeSystem* digRuntimeSystem = createFunction(projectName, vehicleInfo);
827  dlclose(handle);
828  createFunction = NULL;
829  return digRuntimeSystem;
830 #endif
831 #else
832  return nullptr;
833 #endif
834 }
Contains information of a Runner instance.
Definition: IRuntimeContext.h:30
virtual std::shared_ptr< Otx::IProcedure > GetProcedure() const =0
Gets Procedure which created this RuntimeContext by starting an execution.
static void SetLicenseKey(const std::string &licenseKey)
Sets a valid license key to release the API.
static RuntimeConfig & GetInstance()
Get RuntimeConfig Instance
static std::shared_ptr< IRuntimeManager > CreateSocketRuntimeManager(unsigned short otxRunnerPort, unsigned short diagManagerPort)
Creates SocketRuntimeManager with Socket DiagManager.
static std::shared_ptr< IRuntimeManager > CreatePipeRuntimeManager(const std::string &otxRunnerPipeName, const std::string &diagManagerPipeName)
Creates PipeRuntimeManager with Pipe DiagManager.
static std::shared_ptr< IRuntimeManager > CreateRawRuntimeManager()
Creates RawRuntimeManager without DiagManager.
Namespace containing custom implementations
Definition: IRuntimeManager.h:32
Namespace containing all objects related to licensing
Definition: LicenseManager.h:22
Namespace containing the programming interface for browsing and execution of OTX procedures in own ap...
Definition: ClampState.h:7

Example CMake-File

Code example (.\otxruntime\Sample.Console\CMakeLists.txt) of the OTX-Runtime API Sample Program.

1 # Set the project name
2 project (OpenTestSystem.Otx.Runtime2.Api.ReferenceApplication.Cpp)
3 set(UseCompiledApi OFF)
4 
5 ###############################################################################
6 # Source files
7 file(GLOB_RECURSE headers "${PROJECT_SOURCE_DIR}/include/*.h")
8 file(GLOB_RECURSE srcs "${PROJECT_SOURCE_DIR}/src/*.h" "${PROJECT_SOURCE_DIR}/src/*.cpp" "${PROJECT_SOURCE_DIR}/src/*.resx")
9 set(versionInfo ${PROJECT_SOURCE_DIR}/version/version.rc ${PROJECT_SOURCE_DIR}/version/version.h)
10 
11 source_group(
12  TREE ${PROJECT_SOURCE_DIR}/include
13  PREFIX "Include Files"
14  FILES ${headers}
15 )
16 source_group(
17  TREE ${PROJECT_SOURCE_DIR}/src
18  PREFIX "Source Files"
19  FILES ${srcs}
20 )
21 #
22 
23 ###############################################################################
24 # Create the library with the provided sources and headers
25 add_executable(${PROJECT_NAME} ${headers} ${srcs} ${versionInfo} main.cpp)
26 
27 ###############################################################################
28 # DotNet libraries
29 SET(DOTNET_REFERENCES
30  System
31  System.Core
32  System.Data
33  System.Drawing
34  System.Windows.Forms
35 )
36 LIST(JOIN DOTNET_REFERENCES ";" DOTNET_REFERENCES)
37 
38 # Setup CLI
39 set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "sample")
40 set_target_properties(${PROJECT_NAME} PROPERTIES COMMON_LANGUAGE_RUNTIME "")
41 set_target_properties(${PROJECT_NAME} PROPERTIES VS_GLOBAL_CLRSupport "true")
42 set_target_properties(${PROJECT_NAME} PROPERTIES VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.6.1")
43 set_target_properties(${PROJECT_NAME} PROPERTIES VS_DOTNET_REFERENCES "${DOTNET_REFERENCES}")
44 set_target_properties(${PROJECT_NAME} PROPERTIES VS_DOTNET_REFERENCES_COPY_LOCAL OFF)
45 set_target_properties(${PROJECT_NAME} PROPERTIES VS_GLOBAL_ROOTNAMESPACE "OpenTestSystem.Otx.Runtime2.Api.Sample")
46 set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS /ENTRY:main /KEYFILE:${PROJECT_SOURCE_DIR}/key.snk")
47 set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 14)
48 set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD_REQUIRED YES)
49 set_target_properties(${PROJECT_NAME} PROPERTIES CXX_EXTENSIONS NO)
50 
51 include_directories(
52  PUBLIC ${PROJECT_SOURCE_DIR}/include
53  PUBLIC ${PROJECT_SOURCE_DIR}/src
54  ${CMAKE_SOURCE_DIR}/lib/rapidjson-1.1.0/include
55 )
56 
57 if (UseCompiledApi)
58  target_include_directories(${PROJECT_NAME}
59  PRIVATE ${Rt7InstallDir}include/OpenTestSystem.Otx.Runtime2.Api
60  PRIVATE ${Rt7InstallDir}include/CustomImplementations
61  )
62 
63  target_link_libraries(${PROJECT_NAME} ${Rt7InstallDir}lib/OpenTestSystem.Otx.Runtime2.Api.Custom.Default.lib)
64  target_link_libraries(${PROJECT_NAME} ${Rt7InstallDir}lib/OpenTestSystem.Otx.Runtime2.Api.lib)
65 else()
66  # Set include paths
67  target_link_libraries(${PROJECT_NAME} OpenTestSystem.Otx.Runtime2.Api)
68  target_link_libraries(${PROJECT_NAME} OpenTestSystem.Otx.Runtime2.Api.Custom.Default)
69 endif()
70 
71 target_link_libraries(${PROJECT_NAME}
72  ${DiagRuntimeSystemLib}
73  OtxDiagManager::CommandProcessor
74  OtxDiagManager::SystemApi
75  OtxDiagManager::OtxDiagApi
76  OtxDiagManager::NoneOtxDiagApi
77  OtxDiagManager::Common
78 )
79 
80 IF (USE_VWMCDSP)
81  target_compile_definitions(${PROJECT_NAME} PRIVATE USE_VWMCDSP)
82 ENDIF(USE_VWMCDSP)
83 
84 if (UNIX)
85  if (USE_VWMCD_LINK_LIBRARY)
86  target_compile_definitions(${PROJECT_NAME} PRIVATE USE_VWMCD_LINK_LIBRARY)
87  target_link_libraries(${PROJECT_NAME} ${DiagRuntimeSystemLib})
88  elseif(ADD_DL_LIBS)
89  target_link_libraries(${PROJECT_NAME} ${CMAKE_DL_LIBS})
90  endif(USE_VWMCD_LINK_LIBRARY)
91 endif(UNIX)
92 
93 # RT 7 installation: copy to the desired directory
94 add_custom_command(
95  TARGET ${PROJECT_NAME} POST_BUILD
96  COMMAND ${CMAKE_COMMAND} -E copy
97  "$<TARGET_FILE_DIR:${PROJECT_NAME}>/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}"
98  "${Rt7InstallDir}bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}"
99 )
100 
101 # TODO: may be copy OtxDiagManager BINs
Namespace containing all objects which are standardized according to ISO 13209 (OTX)
Namespace containing all objects related to testing inside automotive industry