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>
39 
40 #include <CommandProcessor.h>
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>
58 #else
59 #include <VwMcdDiagRuntimeSystem.h>
61 #endif
62 #else
63 #include <dlfcn.h>
64 void* handle;
65 #endif // USE_VWMCD_LINK_LIBRARY
66 #endif
68 
69 #include "../../../lib/OpenTestSystem.OtxDiagManager.SystemApi/include/Util.h"
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  if (runtimeManager->IsProtected(ptxFile))
408  {
409  std::cout << "Enter password: ";
410  std::string password;
411  std::getline(std::cin, password);
412 
413  project = runtimeManager->LoadPtx(ptxFile, password); // Loads the given PTX file.
414  }
415  else
416  {
417  project = runtimeManager->LoadPtx(ptxFile); // Loads the given PTX file.
418  }
419 
420  break;
421  }
422  catch (std::exception& ex)
423  {
424  std::cerr << "\t" << ex.what() << std::endl;
425  }
426  }
427 
428  if (project)
429  {
430  std::vector<std::shared_ptr<Otx::IProcedure>> procedures = DisplayPtxTree(project); // Display the PTX content
431 
432  // Execute a procedure with diagnostics(not the main)
433  SelectAndExecuteProcedure(runtimeManager, project, procedures);
434  }
435 
436  SingletonManager::Get().DestroyAll(); // Destroy all singletons in the runtime API to ensure a clean shutdown without warnings.
437 #ifdef _WIN32
438  system("pause");
439 #endif
440  delete cp;
441  return EXIT_SUCCESS;
442 }
443 
444 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 = "")
445 {
446  for (int i = 0; i < packages.size(); i++)
447  {
448  std::shared_ptr<Otx::IPackage> package = packages.at(i);
449  std::cout << stringConcat << " |- " << package->GetName() << " (Package)" << std::endl;
450 
451  procedures = DisplayPtxPackageTree(procedures, package->GetPackages(), stringConcat + " |");
452 
453  for (int j = 0; j < package->GetDocuments().size(); j++)
454  {
455  std::shared_ptr<Otx::IDocument> document = package->GetDocuments().at(j);
456  document->GetImports();
457 
458  std::cout << stringConcat << " | |- " << document->GetName() << " (Document)" << std::endl;
459  for (int k = 0; k < document->GetProcedures().size(); k++)
460  {
461  std::shared_ptr<Otx::IProcedure> procedure = document->GetProcedures().at(k);
462  procedures.push_back(procedure);
463  std::cout << stringConcat << " | | |- " << procedure->GetName() << " (Procedure)" << " - code: " << procedures.size() << std::endl;
464 
465  for (int m = 0; m < procedure->GetParameters().size(); m++)
466  {
467  std::shared_ptr<Otx::IProcedureParameter> param = procedure->GetParameters().at(m);
468 
469  std::string name = param->GetName();
470  std::string dataType = param->GetDataType();
471 
472  auto value = param->GetInitValue();
473  std::string valueStr = (value != nullptr ? value->ToLiteralString() : "null");
474 
475  if (std::shared_ptr<Otx::IProcedureInParameter> inParameter = std::dynamic_pointer_cast<Otx::IProcedureInParameter>(param))
476  {
477  std::cout <<
478  stringConcat << " | | | |- " << name << " (" << dataType << "): " << valueStr << " (InParameter or InOutParameter)" << std::endl;
479  }
480  else
481  {
482  std::cout << stringConcat << " | | | |- " << name << " (" << dataType << "): " << valueStr << " (OutParameter)" << std::endl;
483  }
484  }
485  }
486  }
487  }
488  return procedures;
489 }
490 
491 std::vector < std::shared_ptr<Otx::IProcedure>> DisplayPtxTree(std::shared_ptr<Project::IProject> project)
492 {
493  std::vector < std::shared_ptr<Otx::IProcedure>> procedures;
494  if (project != NULL)
495  {
496  std::cout << std::endl << "PTX tree: " << std::endl;
497 
498  std::cout << "- " << project->GetName() << " (Project)" << std::endl;
499 
500  procedures = DisplayPtxPackageTree(procedures, project->GetPackages());
501  }
502  return procedures;
503 }
504 
505 void SelectAndExecuteProcedure(std::shared_ptr<IRuntimeManager> runtimeManager, std::shared_ptr<Project::IProject> project, std::vector<std::shared_ptr<Otx::IProcedure>> procedures)
506 {
507 
508 ReEnterProcedure:
509  std::string procedureFullName;
510  std::cout << std::endl << "Enter Procedure (full name, code or 0 - if exit): ";
511  std::getline(std::cin, procedureFullName);
512 
513  std::shared_ptr<Otx::IProcedure> procedure = nullptr;
514  try
515  {
516  int idxProcedure = std::stoi(procedureFullName.c_str());
517  if (idxProcedure < 0 || idxProcedure>procedures.size() + 1)
518  {
519  std::cout << std::endl << "The procedure code is invalid.";
520  goto ReEnterProcedure;
521  }
522  else if (idxProcedure == 0 && procedureFullName.size() > 0)
523  {
524  return;
525  }
526  else
527  {
528  procedure = procedures.at(idxProcedure - 1); // Select the procedure to execute
529  }
530  }
531  catch (const std::exception&)
532  {
533 
534  }
535 
536  if (procedure != nullptr)
537  {
538  // Set value to procedure parameters
539  for (int i = 0; i < procedure->GetParameters().size(); i++)
540  {
541  std::shared_ptr<Otx::IProcedureParameter> procedureParameter = procedure->GetParameters().at(i);
542  if (std::shared_ptr<Otx::IProcedureInParameter> inParameter = std::dynamic_pointer_cast<Otx::IProcedureInParameter>(procedureParameter))
543  {
544  bool isValidValue = false;
545  do
546  {
547  try
548  {
549  isValidValue = true;
550  std::string value;
551  std::cout << "Enter value of " << procedureParameter->GetName() << " (" << procedureParameter->GetDataType() << "): ";
552  std::getline(std::cin, value);
553  if (value != "")
554  {
555  inParameter->SetValue(ValueConverter::String2Value(value, procedureParameter->GetDataType()));
556  }
557  }
558  catch (std::exception& ex)
559  {
560  isValidValue = false;
561  std::cerr << ex.what() << std::endl;
562  }
563  } while (!isValidValue);
564  }
565  else if (std::shared_ptr<Otx::IProcedureInOutParameter> inOutParameter = std::dynamic_pointer_cast<Otx::IProcedureInOutParameter>(procedureParameter))
566  {
567  bool isValidValue = false;
568  do
569  {
570  try
571  {
572  isValidValue = true;
573  std::string value;
574  std::cout << "Enter value of " << procedureParameter->GetName() << " (" << procedureParameter->GetDataType() << "): ";
575  std::getline(std::cin, value);
576  if (value != "")
577  {
578  inOutParameter->SetValue(ValueConverter::String2Value(value, procedureParameter->GetDataType()));
579  }
580  }
581  catch (std::exception& ex)
582  {
583  isValidValue = false;
584  std::cerr << ex.what() << std::endl;
585  }
586  } while (!isValidValue);
587  }
588  }
589 
590  isProcedureFinished = false;
591  std::shared_ptr<IRuntimeContext> runtimeContext = runtimeManager->ExecuteAsync(procedure); // Execute the selected procedure
592 
593  while (isProcedureFinished == false) // Poll and wait until the procedure finishes.
594  {
595  std::this_thread::sleep_for(std::chrono::milliseconds(1));
596  }
597 
598  if (runtimeContext->HasOtxException()) // Gets the uncatched otx exceptions from the procedure (ablauf) if any
599  {
600  std::cout << std::endl << "Otx exception occurred:" << "\t";
601  std::cout << runtimeContext->GetOtxException().GetOtxType() << ":" << runtimeContext->GetOtxException().what() << std::endl;
602  }
603  else if (runtimeContext->HasRuntimeException()) // Gets the uncatched runtime exceptions in the execution if any
604  {
605  std::cout << std::endl << "Runtime exception occurred:" << "\t";
606  std::cout << runtimeContext->GetRuntimeException().what() << std::endl;
607  }
608  }
609  else
610  {
611  std::cout << "Procedure " << procedureFullName << " does not exist!" << std::endl;
612  }
613 
614  goto ReEnterProcedure;
615 }
616 
617 std::string SelectProject(std::shared_ptr<IDiagConfiguration> diagConfiguration)
618 {
619  std::string projectSelected;
620  int indexProjectSelect = 0;
621 
622  std::shared_ptr<IDiagConfiguration> diagConfig = diagConfiguration;
623  if (diagConfig == NULL)
624  {
625  diagConfig = CreateRawOtxDiag()->GetDiagConfiguration();
626  }
627  std::vector<std::string> projectList = diagConfig->GetDbProjectList(); // Get all available ODX projects for selecting
628 
629  if (projectList.size() > 0)
630  {
631  std::cout << "Select a ODX-Runtime-Project" << std::endl;
632  std::cout << "\t0 - None" << std::endl;
633 
634  for (size_t indexProjectItem = 0; indexProjectItem < projectList.size(); indexProjectItem++)
635  {
636  std::cout << "\t" << indexProjectItem + 1 << " - " << projectList.at(indexProjectItem) << std::endl;
637  }
638 
639 #ifdef _WIN32
640  flushall();
641 #endif
642  std::cout << "Enter a number: ";
643  std::cin >> indexProjectSelect;
644  std::cin.ignore();
645  if (indexProjectSelect > 0 && indexProjectSelect - 1 < projectList.size())
646  {
647  projectSelected = projectList.at(indexProjectSelect - 1);
648  diagConfig->SelectProject(projectSelected);
649  }
650  }
651 
652  return projectSelected;
653 }
654 
655 std::string SelectVehicleInformation(std::shared_ptr<IDiagConfiguration> diagConfiguration)
656 {
657  std::string vehicleSelected;
658  int indexVehicleInformationSelect = 0;
659 
660  std::shared_ptr<IDiagConfiguration> _diagConfiguration = diagConfiguration;
661  if (_diagConfiguration == NULL)
662  {
663  _diagConfiguration = CreateRawOtxDiag()->GetDiagConfiguration();
664  }
665  std::vector<std::string> vehicleInformationList = _diagConfiguration->GetDbVehicleInformationList();
666 
667  for (size_t indexVehicleInformationName = 0; indexVehicleInformationName < vehicleInformationList.size(); indexVehicleInformationName++)
668  {
669  std::cout << "\t" << indexVehicleInformationName + 1 << " - " << vehicleInformationList.at(indexVehicleInformationName) << std::endl;
670  }
671 
672 #ifdef _WIN32
673  flushall();
674 #endif
675  std::cout << "Input vehicle information code: ";
676  std::cin >> indexVehicleInformationSelect;
677  std::cin.ignore();
678  if (indexVehicleInformationSelect > 0 && indexVehicleInformationSelect - 1 < vehicleInformationList.size())
679  {
680  vehicleSelected = vehicleInformationList.at(indexVehicleInformationSelect - 1);
681  _diagConfiguration->SelectVehicleInformation(vehicleSelected);
682  }
683  return vehicleSelected;
684 }
685 
686 std::shared_ptr<IOtxDiag> CreateRawOtxDiag()
687 {
689 
690  if (cp == nullptr)
691  {
692  cp = new CommandProcessor;
693  }
694 
695  bool useVwmcdSP = false;
696 #ifdef USE_VWMCDSP
697  useVwmcdSP = true;
698 #endif
699  OpenTestSystem::Otx::DiagManager::Client::ClientFactory clientFactory;
700  std::shared_ptr<OpenTestSystem::Otx::DiagManager::Client::Client> rawClient = clientFactory.CreateRawClient(cp);
701  Util::SetLicenseKey(rawClient, licenseKey); // use the license key of otx runtime also for diagmanager
702  const char* kernelPath = getenv("VW_MCD_HOME");
703  if (!kernelPath)
704  {
705  std::cout << "\tCannot read ENVIRONMENT VARIABLE 'VW_MCD_HOME'" << std::endl;
706  return nullptr;
707  }
708 
709  const char* configPath = getenv("VW_MCD_CONFIG");
710  if (!configPath)
711  {
712  std::cout << "\tCannot read ENVIRONMENT VARIABLE 'VW_MCD_CONFIG'" << std::endl;
713  return nullptr;
714  }
715 
716  std::cout << "\tVW_MCD_HOME = " << kernelPath << std::endl;
717  std::cout << "\tVW_MCD_CONFIG = " << configPath << std::endl;
718  IDiagRuntimeSystem* drs = CreateDiagRuntimeSystem("", "", kernelPath, useVwmcdSP);
719  if (drs == nullptr)
720  {
721  std::cout << "\tInitDiagRuntimeSystem failed!" << std::endl;
722  return nullptr;
723  }
724  cp->SetRuntimeSystem(drs);
725  return factory.CreateRawOtxDiag(cp);
726 }
727 #ifdef _WIN32
728 std::string GetLastErrorAsString()
729 {
730  //Get the error message ID, if any.
731  DWORD errorMessageID = ::GetLastError();
732  if (errorMessageID == 0) {
733  return std::string(); //No error message has been recorded
734  }
735 
736  LPSTR messageBuffer = nullptr;
737 
738  //Ask Win32 to give us the string version of that message ID.
739  //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).
740  size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
741  NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
742 
743  //Copy the error message into a std::string.
744  std::string message(messageBuffer, size);
745 
746  //Free the Win32's string's buffer.
747  LocalFree(messageBuffer);
748 
749  return message;
750 }
751 #endif
752 
753 IDiagRuntimeSystem* CreateDiagRuntimeSystem(const char* projectName, const char* vehicleInfo, const char* kernelPath, bool useVwmcdSP)
754 {
755 #ifdef _WIN32
756  typedef IDiagRuntimeSystem* (__cdecl* typeCreateDiagRuntimeSystem)(const char* projectName, const char* vehicleInfo);
757  DiagRuntimeSystemDLL = NULL;
758 
759  // represents vwmcd version 17.50.x.x
760  std::string DiagRuntimeSystem_17_50_FileName = "OpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.VwMcd_VC142.dll";
761  // represents vwmcdsp version 17.50.0.x.x
762  std::string DiagRuntimeSystemSP_17_50_FileName = "OpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.VwMcdSP_VC142.dll";
763  // represents vwmcd version 9.00.x.x to 14.00.x.x
764  std::string DiagRuntimeSystem_09_00_FileName = "OpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.dll";
765  // represents vwmcdsp version 9.00.x.x to 14.00.x.x
766  std::string DiagRuntimeSystemSP_09_00_FileName = "OpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.VwMcd90SP.dll";
767 
768  // Default use mcd version 17.50.x.x
769  std::string DiagRuntimeSystemFileName = DiagRuntimeSystem_17_50_FileName;
770  std::string kernelTypeStr = "VwMcd1750";
771 
772  if (useVwmcdSP)
773  {
774  kernelTypeStr = "VwMcd1750SP";
775  DiagRuntimeSystemFileName = DiagRuntimeSystemSP_17_50_FileName;
776  }
777 
778  if (fs::exists(std::string(kernelPath) + "/McdKernel_vc120.dll")) // check vwmcd 90
779  {
780  if (useVwmcdSP)
781  {
782  kernelTypeStr = "VwMcd90SP";
783  DiagRuntimeSystemFileName = DiagRuntimeSystemSP_09_00_FileName;
784  }
785  else
786  {
787  kernelTypeStr = "VwMcd90";
788  DiagRuntimeSystemFileName = DiagRuntimeSystem_09_00_FileName;
789  }
790  }
791 
792  std::cout << "\tKernel Type is " << kernelTypeStr << std::endl;
793 
794  DiagRuntimeSystemDLL = ::LoadLibrary(DiagRuntimeSystemFileName.c_str());
795  if (DiagRuntimeSystemDLL == NULL)
796  {
797  std::string errorMessage = GetLastErrorAsString();
798  std::cout << errorMessage << std::endl;
799  throw std::exception(errorMessage.c_str());
800  }
801 
802  typedef IDiagRuntimeSystem* (__cdecl* typeCreateDiagRuntimeSystem)(const char* projectName, const char* vehicleInfo);
803  typeCreateDiagRuntimeSystem createFunction = reinterpret_cast<typeCreateDiagRuntimeSystem>(::GetProcAddress(DiagRuntimeSystemDLL, "CreateDiagRuntimeSystem"));
804 
805  if (createFunction == nullptr)
806  return nullptr;
807 
808  return createFunction(projectName, vehicleInfo);
809 #elif defined(__linux__) || defined(__QNXNTO__)
810 #ifdef USE_VWMCD_LINK_LIBRARY
811  return new VwMcdDiagRuntimeSystem(projectName, vehicleInfo);
812 #else
813  if (!handle && useVwmcdSP == false)
814  {
815  std::cout << "Kernel Type is VwMcd" << std::endl;
816  handle = dlopen("libOpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.VwMcd.so", RTLD_NOW);
817  }
818  else if (!handle && useVwmcdSP == true)
819  {
820  std::cout << "Kernel Type is VwMcdSP" << std::endl;
821  handle = dlopen("libOpenTestSystem.Otx.DiagManager.DiagRuntimeSystem.VwMcdSP.so", RTLD_NOW);
822  }
823 
824  if (!handle) {
825  /* fail to load the library */
826  std::cout << dlerror() << std::endl;
827  return nullptr;
828  }
829  typedef IDiagRuntimeSystem* typeCreateDiagRuntimeSystem(const char* projectName, const char* vehicleInfo);
830  typeCreateDiagRuntimeSystem* createFunction = reinterpret_cast<typeCreateDiagRuntimeSystem*>(dlsym(handle, "CreateDiagRuntimeSystem"));
831 
832  if (!createFunction)
833  {
834  dlclose(handle);
835  return nullptr;
836  }
837  IDiagRuntimeSystem* digRuntimeSystem = createFunction(projectName, vehicleInfo);
838  dlclose(handle);
839  createFunction = NULL;
840  return digRuntimeSystem;
841 #endif
842 #else
843  return nullptr;
844 #endif
845 }

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
OpenTestSystem::Otx::Runtime::Api::RuntimeConfig::GetInstance
static RuntimeConfig & GetInstance()
Get RuntimeConfig Instance
OpenTestSystem::Otx::DiagManager::DiagRuntimeSystem::VwMcdDiagRuntimeSystem
Contains methods for accessing the VW-MCD
Definition: VwMcdDiagRuntimeSystem.h:31
OpenTestSystem::Otx::Runtime::Api::License
Namespace containing all objects related to licensing
Definition: LicenseManager.h:22
OpenTestSystem::Otx::DiagManager::Common::IDiagRuntimeSystem
Interface which a DiagRuntimeSystem must be implemented
Definition: IDiagRuntimeSystem.h:21
OpenTestSystem::Otx::Runtime::Api::RuntimeManagerFactory::CreateRawRuntimeManager
static std::shared_ptr< IRuntimeManager > CreateRawRuntimeManager()
Creates RawRuntimeManager without DiagManager.
OpenTestSystem::Otx::Runtime::Api::RuntimeManagerFactory::CreateSocketRuntimeManager
static std::shared_ptr< IRuntimeManager > CreateSocketRuntimeManager(unsigned short otxRunnerPort, unsigned short diagManagerPort)
Creates SocketRuntimeManager with Socket DiagManager.
OpenTestSystem::Otx::DiagManager::OtxDiagApi::OtxDiagFactory::CreateRawOtxDiag
API_EXPORTS std::shared_ptr< IOtxDiag > CreateRawOtxDiag(OpenTestSystem::Otx::DiagManager::Common::ICommandProcessor *commandProcessor)
Creates a DiagManager instance inside the same process
OpenTestSystem::Otx::DiagManager::OtxDiagApi
Namespace covering all actions and terms of all diagnostic related OTX extension by an identical meho...
Definition: DiagConnectionState.h:9
OpenTestSystem::Otx::Runtime::Api::Custom
Namespace containing custom implementations
Definition: IRuntimeManager.h:32
OpenTestSystem::Otx::DiagManager::OtxDiagApi::OtxDiagFactory
Factory class for creating the DiagOtxApi
Definition: OtxDiagFactory.h:37
OpenTestSystem::Otx::Runtime::Api::IRuntimeContext
Contains information of a Runner instance.
Definition: IRuntimeContext.h:30
OpenTestSystem::Otx::Runtime::Api::License::LicenseManager::SetLicenseKey
static void SetLicenseKey(const std::string &licenseKey)
Sets a valid license key to release the API.
OpenTestSystem::Otx::DiagManager::DiagRuntimeSystem::VwMcdSPDiagRuntimeSystem
Contains methods for accessing the VW-MCD
Definition: VwMcdSPDiagRuntimeSystem.h:26
OpenTestSystem::Otx::Extensions::HMI::DataTypes::ConfirmationTypes::NO
@ NO
OpenTestSystem::Otx::Extensions::Logging::DataTypes::LogLevels::OFF
@ OFF
OpenTestSystem::Otx::DiagManager::CommandProcessor::CommandProcessor
The interchangeable CommandProcessor contains methods to optimize the access to the diagnostic runtim...
Definition: CommandProcessor.h:39
OpenTestSystem::Otx
Namespace containing all objects which are standardized according to ISO 13209 (OTX)
OpenTestSystem::Otx::Extensions::HMI::DataTypes::ConfirmationTypes::YES
@ YES
OpenTestSystem::Otx::DiagManager::SystemApi::Util
Class for general utils
Definition: Util.h:25
OpenTestSystem::Otx::Core::Visibility::PRIVATE
@ PRIVATE
OpenTestSystem::Otx::Core::Visibility::PUBLIC
@ PUBLIC
OpenTestSystem
Namespace containing all objects related to testing inside automotive industry
OpenTestSystem::Otx::Runtime::Api::IRuntimeContext::GetProcedure
virtual std::shared_ptr< Otx::IProcedure > GetProcedure() const =0
Gets Procedure which created this RuntimeContext by starting an execution.
OpenTestSystem::Otx::Runtime::Api::RuntimeManagerFactory::CreatePipeRuntimeManager
static std::shared_ptr< IRuntimeManager > CreatePipeRuntimeManager(const std::string &otxRunnerPipeName, const std::string &diagManagerPipeName)
Creates PipeRuntimeManager with Pipe DiagManager.
OpenTestSystem::Otx::Runtime::Api
Namespace containing the programming interface for browsing and execution of OTX procedures in own ap...
Definition: ClampState.h:7