diff --git a/.editorconfig b/.editorconfig index 2cb6f2c..8515095 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,14 +1,12 @@ root = true [*] -indent_style = tab +indent_style = space indent_size = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[*.{yml,yaml}] -indent_style = space +[*.{yml,yaml,oclint}] indent_size = 2 - diff --git a/.oclint b/.oclint new file mode 100644 index 0000000..433a7ee --- /dev/null +++ b/.oclint @@ -0,0 +1,7 @@ +disable-rules: + - LongMethod # HighNcssMethod is enough + - AvoidDefaultArgumentsOnVirtualMethods +rule-paths: [] +rule-configurations: + - key: LONG_LINE + value: 120 diff --git a/.travis.yml b/.travis.yml index 31c9508..95bcc77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ before_install: - sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-4.9 90 - g++-4.9 --version - lcov --version + - eval "$(curl -sL https://raw.githubusercontent.com/ryuichis/oclint-cpp-travis-ci-examples/master/oclint-ci-install.sh)" install: - gem install coveralls-lcov @@ -19,9 +20,11 @@ before_script: - mkdir build && cd build - cmake -DCMAKE_BUILD_TYPE:string="Debug" -Dexample:bool=on -Dtests:bool=on .. # - cmake -Dexamples:bool=on .. # cannot build the GUI example + - cp compile_commands.json .. script: - cd $TRAVIS_BUILD_DIR + - oclint-json-compilation-database - cd build - make -j $(nproc) - cd tests diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fbae9f..cc575ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8) # For compatibility with PROJECT_VERSION* variables if((${CMAKE_VERSION} VERSION_GREATER "3.0") OR (${CMAKE_VERSION} VERSION_EQUAL "3.0")) - cmake_policy(SET CMP0048 OLD) + cmake_policy(SET CMP0048 OLD) endif() # Set project name @@ -15,7 +15,7 @@ set(PROJECT_VERSION_PATCH "3") set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") if(${PROJECT_VERSION_PATCH}) - set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") + set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") endif() # Set options @@ -30,27 +30,28 @@ option(tests "Build the unit tests") option(INSTALL_LIB_DIR "Installation directory for libraries") if(${INSTALL_LIB_DIR} STREQUAL "OFF") - set(INSTALL_LIB_DIR "lib") + set(INSTALL_LIB_DIR "lib") endif() # Set build type if("${CMAKE_BUILD_TYPE}" STREQUAL "") - set(CMAKE_BUILD_TYPE "Release") + set(CMAKE_BUILD_TYPE "Release") endif() +set(CMAKE_EXPORT_COMPILE_COMMANDS "ON") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") # Set definitions if(${CMAKE_BUILD_TYPE} STREQUAL "Release") - add_definitions("-O3") + add_definitions("-O3") endif() if(${tests}) - add_definitions("-g -O0") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") + add_definitions("-g -O0") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") endif() add_definitions("-std=c++11") -add_definitions("-Wall -Wextra -pedantic") +add_definitions("-Wall -Wextra -pedantic -Wno-attributes") # Find libraries find_package(Threads) @@ -59,51 +60,51 @@ find_package(Boost 1.54 REQUIRED COMPONENTS system) include_directories(${Boost_INCLUDE_DIR}) if(${examples-only} STREQUAL "OFF") - # Include headers - include_directories("include") - - # Build library - if((${build-library}) OR (${install-headers} STREQUAL "OFF")) - # Find source code - file(GLOB_RECURSE CPPS "src/regilo/*.cpp") - file(GLOB_RECURSE HPPS "include/regilo/*.hpp") - - # Configure files - configure_file("src/regilo/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/gen/regilo/version.cpp") - list(APPEND CPPS "${CMAKE_CURRENT_BINARY_DIR}/gen/regilo/version.cpp") - - # Create library - add_library(${PROJECT_NAME} SHARED ${CPPS} ${HPPS}) - set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") - - # Link libraries - target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT}) - target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) - endif() - - # Install library - if(${install-headers} STREQUAL "OFF") - install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${INSTALL_LIB_DIR}) - endif() - - # Install headers - if(${install-library} STREQUAL "OFF") - install(DIRECTORY include/${PROJECT_NAME}/ DESTINATION include/${PROJECT_NAME}) - endif() + # Include headers + include_directories("include") + + # Build library + if((${build-library}) OR (${install-headers} STREQUAL "OFF")) + # Find source code + file(GLOB_RECURSE CPPS "src/regilo/*.cpp") + file(GLOB_RECURSE HPPS "include/regilo/*.hpp") + + # Configure files + configure_file("src/regilo/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/gen/regilo/version.cpp") + list(APPEND CPPS "${CMAKE_CURRENT_BINARY_DIR}/gen/regilo/version.cpp") + + # Create library + add_library(${PROJECT_NAME} SHARED ${CPPS} ${HPPS}) + set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") + + # Link libraries + target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) + endif() + + # Install library + if(${install-headers} STREQUAL "OFF") + install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${INSTALL_LIB_DIR}) + endif() + + # Install headers + if(${install-library} STREQUAL "OFF") + install(DIRECTORY include/${PROJECT_NAME}/ DESTINATION include/${PROJECT_NAME}) + endif() endif() # Add examples if((${example}) OR (${examples})) - add_subdirectory("examples/regilo-scan") + add_subdirectory("examples/regilo-scan") endif() if((${example-gui}) OR (${examples})) - add_subdirectory("examples/regilo-visual") + add_subdirectory("examples/regilo-visual") endif() # Add unit tests if(${tests}) - add_subdirectory("tests") + add_subdirectory("tests") endif() # Add uninstall diff --git a/README.md b/README.md index 21ae602..c4182d7 100644 --- a/README.md +++ b/README.md @@ -32,15 +32,13 @@ regilo::NeatoSocketController controller; controller.connect("10.0.0.1:12345"); // Set the test mode and LDS rotation -controller.setTestMode(true); -controller.setLdsRotation(true); +controller.startScanner(); // Grab a scan from the robot regilo::ScanData data = controller.getScan(); // Unset the test mode and LDS rotation -controller.setLdsRotation(false); -controller.setTestMode(false); +controller.stopScanner(); ``` ### Hokuyo diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in index 7e56ab3..4300577 100644 --- a/cmake/cmake_uninstall.cmake.in +++ b/cmake/cmake_uninstall.cmake.in @@ -1,22 +1,21 @@ if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif() file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) - message(STATUS "Uninstalling $ENV{DESTDIR}${file}") - if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") - execute_process(COMMAND - @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" - OUTPUT_VARIABLE rm_out - RESULT_VARIABLE rm_resval - ) - if(NOT "${rm_resval}" STREQUAL 0) - message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") - endif() - else() - message(STATUS "File $ENV{DESTDIR}${file} does not exist.") - endif() + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + execute_process(COMMAND + @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_resval + ) + if(NOT "${rm_resval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif() + else() + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif() endforeach() - diff --git a/examples/regilo-scan/src/main.cpp b/examples/regilo-scan/src/main.cpp index c589e6c..547e774 100644 --- a/examples/regilo-scan/src/main.cpp +++ b/examples/regilo-scan/src/main.cpp @@ -33,168 +33,233 @@ struct Arguments { - std::string device; - std::string protocol; - std::string endpoint; - std::string logPath; - bool help = false; + std::string device; + std::string protocol; + std::string endpoint; + std::string logPath; + bool help = false; }; +__attribute__((annotate("oclint:suppress[high ncss method]"))) +int run(const Arguments& args); + void printHelp(); + void parseArgs(int argc, char **argv, Arguments& args); +void parsePosArgs(int argc, char **argv, Arguments& args); + +regilo::IScanController* createController(const Arguments& args); +regilo::ILog* createLog(const Arguments& args); int main(int argc, char **argv) { - std::cout.setf(std::ios_base::boolalpha); - - Arguments args; - try - { - parseArgs(argc, argv, args); - } - catch(std::invalid_argument& e) - { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - - if(args.help) - { - printHelp(); - return 0; - } - - std::cout << "Hello Regilo!" << std::endl; - - bool fromDevice = (args.protocol != "log"); - regilo::IScanController *controller = nullptr; - regilo::INeatoController *neatoController = nullptr; - regilo::IHokuyoController *hokuyoController = nullptr; - - if(args.device == "neato") - { - if(args.protocol == "serial") neatoController = new regilo::NeatoSerialController(); - else neatoController = new regilo::NeatoSocketController(); - - controller = dynamic_cast(neatoController); - } - else if(args.device == "hokuyo") - { - if(args.protocol == "serial") hokuyoController = new regilo::HokuyoSerialController(); - else hokuyoController = new regilo::HokuyoSocketController(); - - controller = dynamic_cast(hokuyoController); - } - - std::cout << "Using " << args.device << ':' << args.protocol << " controller." << std::endl; - std::cout << "Connecting to " << args.endpoint << std::endl; - - regilo::TimedLog<> *log; - if(fromDevice) - { - controller->connect(args.endpoint); - if(!args.logPath.empty()) log = new regilo::TimedLog<>(args.logPath); - } - else log = new regilo::TimedLog<>(args.endpoint); - controller->setLog(std::shared_ptr>(log)); - - if(fromDevice && args.device == "neato") - { - neatoController->setTestMode(true); - std::cout << "Test mode: " << neatoController->getTestMode() << std::endl; - - neatoController->setLdsRotation(true); - std::cout << "LDS rotation: " << neatoController->getLdsRotation() << std::endl; - } - - std::this_thread::sleep_for(std::chrono::seconds(3)); - - regilo::ScanData data = controller->getScan(fromDevice); - std::cout << "Scan data:" << std::endl << data << std::endl; - - if(fromDevice) - { - if(args.device == "neato") - { - neatoController->setLdsRotation(false); - std::cout << "LDS rotation: " << neatoController->getLdsRotation() << std::endl; - - neatoController->setTestMode(false); - std::cout << "Test mode: " << neatoController->getTestMode() << std::endl; - } - else if(args.device == "hokuyo") - { - std::map info = hokuyoController->getVersionInfo(); - std::cout << "Version info: " << std::endl; - for(const auto& kw : info) - { - std::cout << kw.first << " = " << kw.second << std::endl; - } - std::cout << std::endl; - } - } - - delete controller; - - return 0; + std::cout.setf(std::ios_base::boolalpha); + + Arguments args; + try + { + parseArgs(argc - 1, argv + 1, args); + } + catch(std::invalid_argument& e) + { + std::cout << "Error: " << e.what() << std::endl; + return 1; + } + + if(args.help) + { + printHelp(); + return 0; + } + + return run(args); +} + +int run(const Arguments& args) +{ + std::cout << "Hello Regilo!" << std::endl; + + bool fromDevice = args.protocol != "log"; + regilo::IScanController *controller = createController(args); + + std::cout << "Using " << args.device << ':' << args.protocol << " controller." << std::endl; + std::cout << "Connecting to " << args.endpoint << std::endl; + + if(fromDevice) + { + controller->connect(args.endpoint); + } + + controller->setLog(std::shared_ptr(createLog(args))); + + if(fromDevice && args.device == "neato") + { + auto *neatoController = dynamic_cast(controller); + + neatoController->setTestMode(true); + std::cout << "Test mode: " << neatoController->getTestMode() << std::endl; + + neatoController->setLdsRotation(true); + std::cout << "LDS rotation: " << neatoController->getLdsRotation() << std::endl; + } + + if(fromDevice) + { + std::this_thread::sleep_for(std::chrono::seconds(3)); + } + + regilo::ScanData data = controller->getScan(fromDevice); + std::cout << "Scan data:" << std::endl << data << std::endl; + + if(fromDevice) + { + if(args.device == "neato") + { + auto *neatoController = dynamic_cast(controller); + + neatoController->setLdsRotation(false); + std::cout << "LDS rotation: " << neatoController->getLdsRotation() << std::endl; + + neatoController->setTestMode(false); + std::cout << "Test mode: " << neatoController->getTestMode() << std::endl; + } + else if(args.device == "hokuyo") + { + auto *hokuyoController = dynamic_cast(controller); + + std::map info = hokuyoController->getVersionInfo(); + std::cout << "Version info: " << std::endl; + for(const auto& kw : info) + { + std::cout << kw.first << " = " << kw.second << std::endl; + } + std::cout << std::endl; + } + } + + delete controller; + + return 0; } void printHelp() { - std::cout << "Usage: regilo-scan [options] " << std::endl - << "Arguments:" << std::endl - << " The controller name in the format \"device:protocol\". The device" << std::endl - << " part can be \"neato\" or \"hokuyo\". The protocol part can be" << std::endl - << " \"socket\", \"serial\", or \"log\"." << std::endl - << " The endpoint that is used to connect to the device. It can be" << std::endl - << " a path to the device or input log, or ip and port." << std::endl - << std::endl - << "Options:" << std::endl - << " -l The path to the output log file." << std::endl - << " -h, --help Show this help." << std::endl - << std::endl - << "Using regilo-" << regilo::Version::VERSION << std::endl; + std::cout + << "Usage: regilo-scan [options] \n" + "\n" + "Arguments:\n" + " The controller name in the format \"device:protocol\". The device\n" + " part can be \"neato\" or \"hokuyo\". The protocol part can be\n" + " \"socket\", \"serial\", or \"log\".\n" + " The endpoint that is used to connect to the device. It can be\n" + " a path to the device or input log, or ip and port.\n" + "\n" + "Options:\n" + " -l The path to the output log file.\n" + " -h, --help Show this help.\n" + "\n"; + + std::cout << "Using regilo-" << regilo::Version::VERSION << std::endl; } void parseArgs(int argc, char **argv, Arguments& args) { - int posArg = 0; - for(int i = 1; i < argc; i++) - { - std::string arg(argv[i]); - - if(arg == "-l") args.logPath = std::string(argv[++i]); - else if(arg == "-h" || arg == "--help") - { - args.help = true; - return; - } - else if(arg.front() != '-') - { - if(posArg == 0) - { - std::size_t colonPos = arg.find(':'); - if(colonPos == std::string::npos) - throw std::invalid_argument("Missing controller protocol (use \"socket\", \"serial\", or \"log\")."); - - args.device = arg.substr(0, colonPos); - if(args.device != "neato" && args.device != "hokuyo") - throw std::invalid_argument("Unknown controller device (use \"neato\" or \"hokuyo\")."); - - args.protocol = arg.substr(colonPos + 1); - if(args.protocol != "socket" && args.protocol != "serial" && args.protocol != "log") - throw std::invalid_argument("Unknown controller protocol (use \"socket\", \"serial\", or \"log\")."); - } - else if(posArg == 1) args.endpoint = arg; - - posArg++; - } - else throw std::invalid_argument("Unknown argument \"" + arg + "\"."); - } - - if(args.device.empty() || args.protocol.empty()) - throw std::invalid_argument("Missing controller (see -h for more details)."); - - if(args.endpoint.empty()) - throw std::invalid_argument("Missing endpoint (see -h for more details)."); + for(int i = 0; i < argc; i++) + { + std::string arg(argv[i]); + + if(arg == "-l") args.logPath = std::string(argv[++i]); + else if(arg == "-h" || arg == "--help") + { + args.help = true; + return; + } + else if(arg.front() == '-') + { + throw std::invalid_argument("Unknown argument \"" + arg + "\"."); + } + else + { + parsePosArgs(argc - i, argv + i, args); + break; + } + } + + if(args.device.empty() || args.protocol.empty()) + { + throw std::invalid_argument("Missing controller (see -h for more details)."); + } + + if(args.endpoint.empty()) + { + throw std::invalid_argument("Missing endpoint (see -h for more details)."); + } +} + +void parsePosArgs(int argc, char **argv, Arguments& args) +{ + for(int i = 0; i < argc; i++) + { + std::string arg(argv[i]); + + if(i == 0) + { + std::size_t colonPos = arg.find(':'); + if(colonPos == std::string::npos) + { + throw std::invalid_argument("Missing controller protocol (use \"socket\", \"serial\", or \"log\")."); + } + + args.device = arg.substr(0, colonPos); + if(args.device != "neato" && args.device != "hokuyo") + { + throw std::invalid_argument("Unknown controller device (use \"neato\" or \"hokuyo\")."); + } + + args.protocol = arg.substr(colonPos + 1); + if(args.protocol != "socket" && args.protocol != "serial" && args.protocol != "log") + { + throw std::invalid_argument("Unknown controller protocol (use \"socket\", \"serial\", or \"log\")."); + } + } + else if(i == 1) args.endpoint = arg; + } +} + +regilo::IScanController* createController(const Arguments& args) +{ + if(args.device == "neato") + { + if(args.protocol == "serial") return new regilo::NeatoSerialController(); + return new regilo::NeatoSocketController(); + } + + if(args.device == "hokuyo") + { + if(args.protocol == "serial") return new regilo::HokuyoSerialController(); + return new regilo::HokuyoSocketController(); + } + + return nullptr; +} + +regilo::ILog* createLog(const Arguments& args) +{ + regilo::ILog *log = nullptr; + const std::string logPath = args.protocol == "log" ? args.endpoint : args.logPath; + + if(!logPath.empty()) + { + log = new regilo::Log(logPath); + log->readMetadata(); + const std::string& type = log->getMetadata()->getType(); + + if(type == "timedlog") + { + delete log; + log = new regilo::TimedLog<>(logPath); + } + } + + return log; } diff --git a/examples/regilo-visual/CMakeLists.txt b/examples/regilo-visual/CMakeLists.txt index 93b81d0..2a3bf44 100644 --- a/examples/regilo-visual/CMakeLists.txt +++ b/examples/regilo-visual/CMakeLists.txt @@ -28,4 +28,4 @@ target_link_libraries(${PROJECT_NAME} ${wxWidgets_LIBRARIES}) target_link_libraries(${PROJECT_NAME} regilo) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND - ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/images $/images) + ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/images $/images) diff --git a/examples/regilo-visual/include/regilovisual.hpp b/examples/regilo-visual/include/regilovisual.hpp index 6003652..682bbee 100644 --- a/examples/regilo-visual/include/regilovisual.hpp +++ b/examples/regilo-visual/include/regilovisual.hpp @@ -28,7 +28,7 @@ #include #ifndef WX_PRECOMP - #include + #include #endif #include @@ -39,58 +39,59 @@ class wxGCDC; class RegiloVisual : public wxApp { private: - regilo::IScanController *controller; - std::mutex controllerMutex; + regilo::IScanController *controller; + std::mutex controllerMutex; - bool useScanner; - bool manualScanning; - bool moveScanning; + bool useScanner; + bool manualScanning; + bool moveScanning; - wxFrame *frame; - wxPanel *panel; - bool fullscreen; - double zoom; + wxFrame *frame; + wxPanel *panel; + bool fullscreen = false; + double zoom = 0.08; - regilo::ScanData data; + regilo::ScanData data; - std::thread scanThread; - bool scanThreadRunning; - std::condition_variable scanThreadCV; - std::mutex scanThreadCVMutex; + std::thread scanThread; + bool scanThreadRunning; + std::condition_variable scanThreadCV; + std::mutex scanThreadCVMutex; - wxColour radarColor, pointColor; + wxColour radarColor = wxColour(0, 200, 0); + wxColour pointColor = wxColour(200, 200, 200); - double radarAngle; - double radarRayLength; - std::mutex radarMutex; - std::thread radarThread; - std::condition_variable radarThreadCV; - std::mutex radarThreadCVMutex; + double radarAngle = 0; + double radarRayLength = 4000; + std::mutex radarMutex; + std::thread radarThread; + std::condition_variable radarThreadCV; + std::mutex radarThreadCVMutex; - wxImage radarGradient; - wxImage radarGradientZoom; + wxImage radarGradient; + wxImage radarGradientZoom; - void stopScanThread(); - void scanAndShow(); + void stopScanThread(); + void scanAndShow(); - wxImage zoomImage(const wxImage& image, double zoom); + wxImage zoomImage(const wxImage& image, double zoom); - wxRect getRotatedBoundingBox(const wxRect& rect, double angle); - void drawRadarGradient(wxDC& dc, int width2, int height2); + wxRect getRotatedBoundingBox(const wxRect& rect, double angle); + void drawRadarGradient(wxDC& dc, int width2, int height2); - void setStatusText(const std::string& text, int i = 0); - void refreshStatusBar(); + void setStatusText(const std::string& text, int number = 0); + void refreshStatusBar(); public: - RegiloVisual(regilo::IScanController *controller, bool useScanner = true, bool manualScanning = false, bool moveScanning = false); + RegiloVisual(regilo::IScanController *controller, bool useScanner = true, bool manualScanning = false, bool moveScanning = false); - virtual bool OnInit(); - virtual int OnExit(); + virtual bool OnInit(); + virtual int OnExit(); - void setMotorByKey(wxKeyEvent& keyEvent); - void repaint(wxPaintEvent& paintEvent); + void setMotorByKey(wxKeyEvent& keyEvent); + void repaint(wxPaintEvent& paintEvent); - static void Display(wxApp *app, int& argc, char **argv); + static void Display(wxApp *app, int& argc, char **argv); }; #endif // REGILOVISUAL_HPP diff --git a/examples/regilo-visual/src/main.cpp b/examples/regilo-visual/src/main.cpp index 25e2903..27b8a74 100644 --- a/examples/regilo-visual/src/main.cpp +++ b/examples/regilo-visual/src/main.cpp @@ -33,159 +33,220 @@ struct Arguments { - std::string device; - std::string protocol; - std::string endpoint; - std::string logPath; - bool manualScanning = false; - bool autoScanning = false; - bool help = false; + std::string device; + std::string protocol; + std::string endpoint; + std::string logPath; + bool manualScanning = false; + bool autoScanning = false; + bool help = false; }; +int run(int argc, char **argv, const Arguments& args); + void printHelp(); + +__attribute__((annotate("oclint:suppress[high cyclomatic complexity]"))) void parseArgs(int argc, char **argv, Arguments& args); +void parsePosArgs(int argc, char **argv, Arguments& args); + +regilo::IScanController* createController(const Arguments& args); +regilo::ILog* createLog(const Arguments& args); + int main(int argc, char **argv) { - std::cout.setf(std::ios_base::boolalpha); - - Arguments args; - try - { - parseArgs(argc, argv, args); - } - catch(std::invalid_argument& e) - { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - - if(args.help) - { - printHelp(); - return 0; - } - - std::cout << "Hello Regilo!" << std::endl; - - bool fromDevice = (args.protocol != "log"); - regilo::IScanController *controller = nullptr; - regilo::INeatoController *neatoController = nullptr; - regilo::IHokuyoController *hokuyoController = nullptr; - - if(args.device == "neato") - { - if(args.protocol == "serial") neatoController = new regilo::NeatoSerialController(); - else neatoController = new regilo::NeatoSocketController(); - - controller = dynamic_cast(neatoController); - } - else if(args.device == "hokuyo") - { - if(args.protocol == "serial") hokuyoController = new regilo::HokuyoSerialController(); - else hokuyoController = new regilo::HokuyoSocketController(); - - controller = dynamic_cast(hokuyoController); - } - - std::cout << "Using " << args.device << ':' << args.protocol << " controller." << std::endl; - std::cout << "Connecting to " << args.endpoint << std::endl; - - regilo::TimedLog<> *log; - if(fromDevice) - { - controller->connect(args.endpoint); - if(!args.logPath.empty()) log = new regilo::TimedLog<>(args.logPath); - } - else log = new regilo::TimedLog<>(args.endpoint); - controller->setLog(std::shared_ptr>(log)); - - if(fromDevice && args.device == "neato") - { - neatoController->setTestMode(true); - std::cout << "Test mode: " << neatoController->getTestMode() << std::endl; - - neatoController->setLdsRotation(true); - std::cout << "LDS rotation: " << neatoController->getLdsRotation() << std::endl; - } - - RegiloVisual *app = new RegiloVisual(controller, fromDevice, args.manualScanning, args.autoScanning); - RegiloVisual::Display(app, argc, argv); - - if(fromDevice && args.device == "neato") - { - neatoController->setLdsRotation(false); - std::cout << "LDS rotation: " << neatoController->getLdsRotation() << std::endl; - - neatoController->setTestMode(false); - std::cout << "Test mode: " << neatoController->getTestMode() << std::endl; - } - - delete controller; - - return 0; + std::cout.setf(std::ios_base::boolalpha); + + Arguments args; + try + { + parseArgs(argc - 1, argv + 1, args); + } + catch(std::invalid_argument& e) + { + std::cout << "Error: " << e.what() << std::endl; + return 1; + } + + if(args.help) + { + printHelp(); + return 0; + } + + return run(argc, argv, args); +} + +int run(int argc, char **argv, const Arguments& args) +{ + std::cout << "Hello Regilo!" << std::endl; + + bool fromDevice = args.protocol != "log"; + regilo::IScanController *controller = createController(args); + + std::cout << "Using " << args.device << ':' << args.protocol << " controller." << std::endl; + std::cout << "Connecting to " << args.endpoint << std::endl; + + if(fromDevice) + { + controller->connect(args.endpoint); + } + + controller->setLog(std::shared_ptr(createLog(args))); + + if(fromDevice && args.device == "neato") + { + auto *neatoController = dynamic_cast(controller); + + neatoController->setTestMode(true); + std::cout << "Test mode: " << neatoController->getTestMode() << std::endl; + + neatoController->setLdsRotation(true); + std::cout << "LDS rotation: " << neatoController->getLdsRotation() << std::endl; + } + + RegiloVisual *app = new RegiloVisual(controller, fromDevice, args.manualScanning, args.autoScanning); + RegiloVisual::Display(app, argc, argv); + + if(fromDevice && args.device == "neato") + { + auto *neatoController = dynamic_cast(controller); + + neatoController->setLdsRotation(false); + std::cout << "LDS rotation: " << neatoController->getLdsRotation() << std::endl; + + neatoController->setTestMode(false); + std::cout << "Test mode: " << neatoController->getTestMode() << std::endl; + } + + delete controller; + + return 0; } void printHelp() { - std::cout << "Usage: regilo-visual [options] " << std::endl - << "Arguments:" << std::endl - << " The controller name in the format \"device:protocol\". The device" << std::endl - << " part can be \"neato\" or \"hokuyo\". The protocol part can be" << std::endl - << " \"socket\", \"serial\", or \"log\"." << std::endl - << " The endpoint that is used to connect to the device. It can be" << std::endl - << " a path to the device or input log, or ip and port." << std::endl - << std::endl - << "Options:" << std::endl - << " -l The path to the output log file." << std::endl - << " -m Turn on manual scanning (by pressing key S)." << std::endl - << " -a Turn on automatic scanning before move." << std::endl - << " -h, --help Show this help." << std::endl - << std::endl - << "Using regilo-" << regilo::Version::VERSION << std::endl; + std::cout + << "Usage: regilo-visual [options] \n" + "\n" + "Arguments:\n" + " The controller name in the format \"device:protocol\". The device\n" + " part can be \"neato\" or \"hokuyo\". The protocol part can be\n" + " \"socket\", \"serial\", or \"log\".\n" + " The endpoint that is used to connect to the device. It can be\n" + " a path to the device or input log, or ip and port.\n" + "\n" + "Options:\n" + " -l The path to the output log file.\n" + " -m Turn on manual scanning (by pressing key S).\n" + " -a Turn on automatic scanning before move.\n" + " -h, --help Show this help.\n" + "\n"; + + std::cout << "Using regilo-" << regilo::Version::VERSION << std::endl; } void parseArgs(int argc, char **argv, Arguments& args) { - int posArg = 0; - for(int i = 1; i < argc; i++) - { - std::string arg(argv[i]); - - if(arg == "-l") args.logPath = std::string(argv[++i]); - else if(arg == "-m") args.manualScanning = true; - else if(arg == "-a") args.autoScanning = true; - else if(arg == "-h" || arg == "--help") - { - args.help = true; - return; - } - else if(arg.front() != '-') - { - if(posArg == 0) - { - std::size_t colonPos = arg.find(':'); - if(colonPos == std::string::npos) - throw std::invalid_argument("Missing controller protocol (use \"socket\", \"serial\", or \"log\")."); - - args.device = arg.substr(0, colonPos); - if(args.device != "neato" && args.device != "hokuyo") - throw std::invalid_argument("Unknown controller device (use \"neato\" or \"hokuyo\")."); - - args.protocol = arg.substr(colonPos + 1); - if(args.protocol != "socket" && args.protocol != "serial" && args.protocol != "log") - throw std::invalid_argument("Unknown controller protocol (use \"socket\", \"serial\", or \"log\")."); - } - else if(posArg == 1) args.endpoint = arg; - - posArg++; - } - else throw std::invalid_argument("Unknown argument \"" + arg + "\"."); - } - - if(args.device.empty() || args.protocol.empty()) - throw std::invalid_argument("Missing controller (see -h for more details)."); - - if(args.endpoint.empty()) - throw std::invalid_argument("Missing endpoint (see -h for more details)."); + for(int i = 0; i < argc; i++) + { + std::string arg(argv[i]); + + if(arg == "-l") args.logPath = std::string(argv[++i]); + else if(arg == "-m") args.manualScanning = true; + else if(arg == "-a") args.autoScanning = true; + else if(arg == "-h" || arg == "--help") + { + args.help = true; + return; + } + else if(arg.front() == '-') + { + throw std::invalid_argument("Unknown argument \"" + arg + "\"."); + } + else + { + parsePosArgs(argc - i, argv + i, args); + break; + } + } + + if(args.device.empty() || args.protocol.empty()) + { + throw std::invalid_argument("Missing controller (see -h for more details)."); + } + + if(args.endpoint.empty()) + { + throw std::invalid_argument("Missing endpoint (see -h for more details)."); + } +} + +void parsePosArgs(int argc, char **argv, Arguments& args) +{ + for(int i = 0; i < argc; i++) + { + std::string arg(argv[i]); + + if(i == 0) + { + std::size_t colonPos = arg.find(':'); + if(colonPos == std::string::npos) + { + throw std::invalid_argument("Missing controller protocol (use \"socket\", \"serial\", or \"log\")."); + } + + args.device = arg.substr(0, colonPos); + if(args.device != "neato" && args.device != "hokuyo") + { + throw std::invalid_argument("Unknown controller device (use \"neato\" or \"hokuyo\")."); + } + + args.protocol = arg.substr(colonPos + 1); + if(args.protocol != "socket" && args.protocol != "serial" && args.protocol != "log") + { + throw std::invalid_argument("Unknown controller protocol (use \"socket\", \"serial\", or \"log\")."); + } + } + else if(i == 1) args.endpoint = arg; + } +} + +regilo::IScanController* createController(const Arguments& args) +{ + if(args.device == "neato") + { + if(args.protocol == "serial") return new regilo::NeatoSerialController(); + return new regilo::NeatoSocketController(); + } + + if(args.device == "hokuyo") + { + if(args.protocol == "serial") return new regilo::HokuyoSerialController(); + return new regilo::HokuyoSocketController(); + } + + return nullptr; +} + +regilo::ILog* createLog(const Arguments& args) +{ + regilo::ILog *log = nullptr; + const std::string logPath = args.protocol == "log" ? args.endpoint : args.logPath; + + if(!logPath.empty()) + { + log = new regilo::Log(logPath); + log->readMetadata(); + const std::string& type = log->getMetadata()->getType(); + + if(type == "timedlog") + { + delete log; + log = new regilo::TimedLog<>(logPath); + } + } + + return log; } diff --git a/examples/regilo-visual/src/regilovisual.cpp b/examples/regilo-visual/src/regilovisual.cpp index aaaf662..d8ed671 100644 --- a/examples/regilo-visual/src/regilovisual.cpp +++ b/examples/regilo-visual/src/regilovisual.cpp @@ -30,402 +30,426 @@ #include #include -RegiloVisual::RegiloVisual(regilo::IScanController *controller, bool useScanner, bool manualScanning, bool moveScanning) : wxApp(), - controller(controller), useScanner(useScanner), manualScanning(manualScanning), moveScanning(moveScanning), - fullscreen(false), zoom(0.08), - radarColor(0, 200, 0), pointColor(200, 200, 200), radarAngle(0), radarRayLength(4000) +RegiloVisual::RegiloVisual( + regilo::IScanController *controller, + bool useScanner, + bool manualScanning, + bool moveScanning +) : wxApp(), + controller(controller), + useScanner(useScanner), + manualScanning(manualScanning), + moveScanning(moveScanning) { } +__attribute__((annotate("oclint:suppress[high cyclomatic complexity]"))) bool RegiloVisual::OnInit() { - wxPathList pathList; - pathList.Add("."); - pathList.Add(wxStandardPaths::Get().GetResourcesDir()); - - wxInitAllImageHandlers(); - radarGradient.LoadFile(pathList.FindValidPath("images/radar-gradient.png")); - radarGradientZoom = zoomImage(radarGradient, zoom * 10); - - // Frame - frame = new wxFrame(NULL, wxID_ANY, "Regilo Visual", wxDefaultPosition, wxSize(600, 400)); - - // Frame StatusBar - frame->CreateStatusBar(2, wxSTB_ELLIPSIZE_MIDDLE | wxSTB_SHOW_TIPS | wxFULL_REPAINT_ON_RESIZE); - - std::string endpoint; - if(useScanner) endpoint = controller->getEndpoint(); - else endpoint = controller->getLog()->getFilePath(); - - setStatusText("", 0); - setStatusText("Connected to " + endpoint, 1); - - // Panel - panel = new wxPanel(frame); - panel->GetEventHandler()->Bind(wxEVT_KEY_UP, &RegiloVisual::setMotorByKey, this); - panel->GetEventHandler()->Bind(wxEVT_PAINT, &RegiloVisual::repaint, this); - panel->GetEventHandler()->Bind(wxEVT_LEFT_DCLICK, [this] (wxMouseEvent&) - { - if((zoom * 2) > 2) return; - - zoom *= 2; - radarGradientZoom = zoomImage(radarGradient, zoom * 10); - - int width, height; - panel->GetSize(&width, &height); - double maxWidth = std::sqrt(std::pow(width / 2, 2) + std::pow(height / 2, 2)); - - if(radarGradientZoom.GetWidth() > maxWidth) - { - double scale = maxWidth / radarGradientZoom.GetWidth(); - radarGradientZoom.Resize(radarGradientZoom.GetSize() * scale, wxPoint()); - } - }); - panel->GetEventHandler()->Bind(wxEVT_RIGHT_DCLICK, [this] (wxMouseEvent&) - { - if((zoom * 0.5) < 0.002) return; - - zoom *= 0.5; - radarGradientZoom = zoomImage(radarGradient, zoom * 10); - - int width, height; - panel->GetSize(&width, &height); - double maxWidth = std::sqrt(std::pow(width / 2, 2) + std::pow(height / 2, 2)); - - if(radarGradientZoom.GetWidth() > maxWidth) - { - double scale = maxWidth / radarGradientZoom.GetWidth(); - radarGradientZoom.Resize(radarGradientZoom.GetSize() * scale, wxPoint()); - } - }); - - if(!manualScanning && !moveScanning) - { - scanThreadRunning = true; - scanThread = std::thread([this] () - { - while(scanThreadRunning) - { - scanAndShow(); - - if(scanThreadRunning) - { - std::unique_lock lock(scanThreadCVMutex); - scanThreadCV.wait_for(lock, std::chrono::milliseconds(500)); - } - } - }); - } - - std::size_t fps = 24; - radarThread = std::thread([this, fps] () - { - while(scanThreadRunning) - { - radarMutex.lock(); - radarAngle += M_PI / fps / 2; - radarMutex.unlock(); - - this->GetTopWindow()->GetEventHandler()->CallAfter([this] () - { - frame->Refresh(); - }); - - if(scanThreadRunning) - { - std::unique_lock lock(radarThreadCVMutex); - radarThreadCV.wait_for(lock, std::chrono::milliseconds(1000 / fps)); - } - } - }); - - frame->Show(true); - - return true; + wxPathList pathList; + pathList.Add("."); + pathList.Add(wxStandardPaths::Get().GetResourcesDir()); + + wxInitAllImageHandlers(); + radarGradient.LoadFile(pathList.FindValidPath("images/radar-gradient.png")); + radarGradientZoom = zoomImage(radarGradient, zoom * 10); + + // Frame + frame = new wxFrame(NULL, wxID_ANY, "Regilo Visual", wxDefaultPosition, wxSize(600, 400)); + + // Frame StatusBar + frame->CreateStatusBar(2, wxSTB_ELLIPSIZE_MIDDLE | wxSTB_SHOW_TIPS | wxFULL_REPAINT_ON_RESIZE); + + std::string endpoint; + if(useScanner) endpoint = controller->getEndpoint(); + else endpoint = controller->getLog()->getFilePath(); + + setStatusText("", 0); + setStatusText("Connected to " + endpoint, 1); + + // Panel + panel = new wxPanel(frame); + panel->GetEventHandler()->Bind(wxEVT_KEY_UP, &RegiloVisual::setMotorByKey, this); + panel->GetEventHandler()->Bind(wxEVT_PAINT, &RegiloVisual::repaint, this); + panel->GetEventHandler()->Bind(wxEVT_LEFT_DCLICK, [this] (wxMouseEvent&) + { + if((zoom * 2) > 2) return; + + zoom *= 2; + radarGradientZoom = zoomImage(radarGradient, zoom * 10); + + int width, height; + panel->GetSize(&width, &height); + double maxWidth = std::sqrt(std::pow(width / 2, 2) + std::pow(height / 2, 2)); + + if(radarGradientZoom.GetWidth() > maxWidth) + { + double scale = maxWidth / radarGradientZoom.GetWidth(); + radarGradientZoom.Resize(radarGradientZoom.GetSize() * scale, wxPoint()); + } + }); + panel->GetEventHandler()->Bind(wxEVT_RIGHT_DCLICK, [this] (wxMouseEvent&) + { + if((zoom * 0.5) < 0.002) return; + + zoom *= 0.5; + radarGradientZoom = zoomImage(radarGradient, zoom * 10); + + int width, height; + panel->GetSize(&width, &height); + double maxWidth = std::sqrt(std::pow(width / 2, 2) + std::pow(height / 2, 2)); + + if(radarGradientZoom.GetWidth() > maxWidth) + { + double scale = maxWidth / radarGradientZoom.GetWidth(); + radarGradientZoom.Resize(radarGradientZoom.GetSize() * scale, wxPoint()); + } + }); + + if(!manualScanning && !moveScanning) + { + scanThreadRunning = true; + scanThread = std::thread([this] () + { + while(scanThreadRunning) + { + scanAndShow(); + + if(scanThreadRunning) + { + std::unique_lock lock(scanThreadCVMutex); + scanThreadCV.wait_for(lock, std::chrono::milliseconds(500)); + } + } + }); + } + + std::size_t fps = 24; + radarThread = std::thread([this, fps] () + { + while(scanThreadRunning) + { + radarMutex.lock(); + radarAngle += M_PI / fps / 2; + radarMutex.unlock(); + + this->GetTopWindow()->GetEventHandler()->CallAfter([this] () + { + frame->Refresh(); + }); + + if(scanThreadRunning) + { + std::unique_lock lock(radarThreadCVMutex); + radarThreadCV.wait_for(lock, std::chrono::milliseconds(1000 / fps)); + } + } + }); + + frame->Show(true); + + return true; } int RegiloVisual::OnExit() { - stopScanThread(); - if(scanThread.joinable()) scanThread.join(); - if(radarThread.joinable()) radarThread.join(); + stopScanThread(); + if(scanThread.joinable()) scanThread.join(); + if(radarThread.joinable()) radarThread.join(); - return wxApp::OnExit(); + return wxApp::OnExit(); } +__attribute__(( + annotate("oclint:suppress[high npath complexity]"), + annotate("oclint:suppress[high ncss method]"), + annotate("oclint:suppress[high cyclomatic complexity]") +)) void RegiloVisual::setMotorByKey(wxKeyEvent& keyEvent) { - int keyCode = keyEvent.GetKeyCode(); - - if(keyCode == WXK_UP || keyCode == WXK_DOWN || keyCode == WXK_LEFT || keyCode == WXK_RIGHT) - { - if(moveScanning) - { - setStatusText("Move scanning...", 0); - scanAndShow(); - } - } - - regilo::INeatoController *neatoController = dynamic_cast*>(controller); - if(neatoController == nullptr) neatoController = dynamic_cast*>(controller); - - switch(keyCode) - { - case WXK_UP: - if(neatoController != nullptr) - { - controllerMutex.lock(); - setStatusText("Going up...", 0); - - if(keyEvent.ControlDown()) neatoController->setMotor(500, 500, 100); - else neatoController->setMotor(100, 100, 50); - - setStatusText("Going up... Done!", 0); - controllerMutex.unlock(); - } - break; - - case WXK_DOWN: - if(neatoController != nullptr) - { - controllerMutex.lock(); - setStatusText("Going down...", 0); - - neatoController->setMotor(-100, -100, 50); - - setStatusText("Going down... Done!", 0); - controllerMutex.unlock(); - } - break; - - case WXK_LEFT: - if(neatoController != nullptr) - { - controllerMutex.lock(); - setStatusText("Turning left...", 0); - - if(keyEvent.ControlDown()) neatoController->setMotor(-30, 30, 50); - else neatoController->setMotor(20, 100, 50); - - setStatusText("Turning left... Done!", 0); - controllerMutex.unlock(); - } - break; - - case WXK_RIGHT: - if(neatoController != nullptr) - { - controllerMutex.lock(); - setStatusText("Turning right...", 0); - - if(keyEvent.ControlDown()) neatoController->setMotor(30, -30, 50); - else neatoController->setMotor(100, 20, 50); - - setStatusText("Turning right... Done!", 0); - controllerMutex.unlock(); - } - break; - - case WXK_SPACE: - if(neatoController != nullptr) - { - controllerMutex.lock(); - setStatusText("Stopping...", 0); - - neatoController->setMotor(0, 0, 0); - - setStatusText("Stopping... Done!", 0); - controllerMutex.unlock(); - } - break; - - case 'S': - if(manualScanning) - { - setStatusText("Manual scanning...", 0); - scanAndShow(); - } - break; - - case WXK_F11: - fullscreen = !fullscreen; - frame->ShowFullScreen(fullscreen); - break; - - case WXK_ESCAPE: - fullscreen = false; - frame->ShowFullScreen(fullscreen); - break; - - default: - keyEvent.Skip(); - } + int keyCode = keyEvent.GetKeyCode(); + bool isArrow = keyCode == WXK_UP + || keyCode == WXK_DOWN + || keyCode == WXK_LEFT + || keyCode == WXK_RIGHT; + + if(moveScanning && isArrow) + { + setStatusText("Move scanning...", 0); + scanAndShow(); + } + + regilo::INeatoController *neatoController = dynamic_cast(controller); + if(neatoController == nullptr) + { + neatoController = dynamic_cast(controller); + } + + switch(keyCode) + { + case WXK_UP: + if(neatoController != nullptr) + { + controllerMutex.lock(); + setStatusText("Going up...", 0); + + if(keyEvent.ControlDown()) neatoController->setMotor(500, 500, 100); + else neatoController->setMotor(100, 100, 50); + + setStatusText("Going up... Done!", 0); + controllerMutex.unlock(); + } + break; + + case WXK_DOWN: + if(neatoController != nullptr) + { + controllerMutex.lock(); + setStatusText("Going down...", 0); + + neatoController->setMotor(-100, -100, 50); + + setStatusText("Going down... Done!", 0); + controllerMutex.unlock(); + } + break; + + case WXK_LEFT: + if(neatoController != nullptr) + { + controllerMutex.lock(); + setStatusText("Turning left...", 0); + + if(keyEvent.ControlDown()) neatoController->setMotor(-30, 30, 50); + else neatoController->setMotor(20, 100, 50); + + setStatusText("Turning left... Done!", 0); + controllerMutex.unlock(); + } + break; + + case WXK_RIGHT: + if(neatoController != nullptr) + { + controllerMutex.lock(); + setStatusText("Turning right...", 0); + + if(keyEvent.ControlDown()) neatoController->setMotor(30, -30, 50); + else neatoController->setMotor(100, 20, 50); + + setStatusText("Turning right... Done!", 0); + controllerMutex.unlock(); + } + break; + + case WXK_SPACE: + if(neatoController != nullptr) + { + controllerMutex.lock(); + setStatusText("Stopping...", 0); + + neatoController->setMotor(0, 0, 0); + + setStatusText("Stopping... Done!", 0); + controllerMutex.unlock(); + } + break; + + case 'S': + if(manualScanning) + { + setStatusText("Manual scanning...", 0); + scanAndShow(); + } + break; + + case WXK_F11: + fullscreen = !fullscreen; + frame->ShowFullScreen(fullscreen); + break; + + case WXK_ESCAPE: + fullscreen = false; + frame->ShowFullScreen(fullscreen); + break; + + default: + keyEvent.Skip(); + break; + } } wxImage RegiloVisual::zoomImage(const wxImage& image, double zoom) { - wxImage zoomedImage = image; - zoomedImage.Rescale(int(image.GetWidth() * zoom), int(image.GetHeight() * zoom)); + wxImage zoomedImage = image; + zoomedImage.Rescale(int(image.GetWidth() * zoom), int(image.GetHeight() * zoom)); - return zoomedImage; + return zoomedImage; } wxRect RegiloVisual::getRotatedBoundingBox(const wxRect& rect, double angle) { - double c = std::cos(angle); - double s = std::sin(angle); - - wxPoint minBound(std::numeric_limits::max(), std::numeric_limits::max()); - wxPoint maxBound(std::numeric_limits::min(), std::numeric_limits::min()); - - wxPoint points[] = { rect.GetLeftTop(), rect.GetLeftBottom(), rect.GetRightTop(), rect.GetRightBottom() }; - for(wxPoint& point : points) - { - int x = int(std::ceil(c * point.x - s * point.y)); - int y = int(std::ceil(s * point.x + c * point.y)); - - if(x < minBound.x) minBound.x = x; - if(y < minBound.y) minBound.y = y; - if(x > maxBound.x) maxBound.x = x; - if(y > maxBound.y) maxBound.y = y; - - point.x = x; - point.y = y; - } - - wxRect box; - box.SetLeftTop(minBound); - box.SetRightBottom(maxBound); - - return box; + double cosine = std::cos(angle); + double sine = std::sin(angle); + + wxPoint minBound(std::numeric_limits::max(), std::numeric_limits::max()); + wxPoint maxBound(std::numeric_limits::min(), std::numeric_limits::min()); + + wxPoint points[] = + { + rect.GetLeftTop(), + rect.GetLeftBottom(), + rect.GetRightTop(), + rect.GetRightBottom() + }; + + for(wxPoint& point : points) + { + int rotatedX = int(std::ceil(cosine * point.x - sine * point.y)); + int rotatedY = int(std::ceil(sine * point.x + cosine * point.y)); + + if(rotatedX < minBound.x) minBound.x = rotatedX; + if(rotatedY < minBound.y) minBound.y = rotatedY; + if(rotatedX > maxBound.x) maxBound.x = rotatedX; + if(rotatedY > maxBound.y) maxBound.y = rotatedY; + + point.x = rotatedX; + point.y = rotatedY; + } + + wxRect box; + box.SetLeftTop(minBound); + box.SetRightBottom(maxBound); + + return box; } -void RegiloVisual::drawRadarGradient(wxDC& dc, int width2, int height2) +void RegiloVisual::drawRadarGradient(wxDC& context, int width2, int height2) { - wxImage rotatedImage = radarGradientZoom.Rotate(radarAngle, wxPoint()); + wxImage rotatedImage = radarGradientZoom.Rotate(radarAngle, wxPoint()); - wxRect box(radarGradientZoom.GetSize()); - box.width++; - box.height++; - wxRect rotatedBox = getRotatedBoundingBox(box, -radarAngle); + wxRect box(radarGradientZoom.GetSize()); + box.width++; + box.height++; + wxRect rotatedBox = getRotatedBoundingBox(box, -radarAngle); - wxPoint offset = rotatedBox.GetLeftTop(); - offset.x += width2 - 1; - offset.y += height2 - 1; + wxPoint offset = rotatedBox.GetLeftTop(); + offset.x += width2 - 1; + offset.y += height2 - 1; - dc.DrawBitmap(wxBitmap(rotatedImage), offset); + context.DrawBitmap(wxBitmap(rotatedImage), offset); } void RegiloVisual::repaint(wxPaintEvent&) { - wxPaintDC dc(panel); - wxGCDC gcdc(dc); + wxPaintDC paintContext(panel); + wxGCDC graphicsContext(paintContext); - // Draw backgroud - dc.SetBrush(*wxBLACK_BRUSH); - dc.DrawRectangle(panel->GetSize()); + // Draw backgroud + paintContext.SetBrush(*wxBLACK_BRUSH); + paintContext.DrawRectangle(panel->GetSize()); - int width, height; - panel->GetSize(&width, &height); + int width, height; + panel->GetSize(&width, &height); - int width2 = width / 2; - int height2 = height / 2; + int width2 = width / 2; + int height2 = height / 2; - // Draw axis - dc.SetPen(*wxThePenList->FindOrCreatePen(radarColor, 2)); - dc.DrawLine(0, height2, width, height2); - dc.DrawLine(width2, 0, width2, height); + // Draw axis + paintContext.SetPen(*wxThePenList->FindOrCreatePen(radarColor, 2)); + paintContext.DrawLine(0, height2, width, height2); + paintContext.DrawLine(width2, 0, width2, height); - // Draw circles - gcdc.SetPen(*wxThePenList->FindOrCreatePen(radarColor, 2)); - gcdc.SetBrush(*wxTRANSPARENT_BRUSH); - for(std::size_t radius = 1000; radius <= 4000; radius += 1000) - { - gcdc.DrawCircle(width2, height2, int(radius * zoom)); - } + // Draw circles + graphicsContext.SetPen(*wxThePenList->FindOrCreatePen(radarColor, 2)); + graphicsContext.SetBrush(*wxTRANSPARENT_BRUSH); + for(std::size_t radius = 1000; radius <= 4000; radius += 1000) + { + graphicsContext.DrawCircle(width2, height2, int(radius * zoom)); + } - // Draw radar ray - radarMutex.lock(); + // Draw radar ray + radarMutex.lock(); - double rayLength = zoom * radarRayLength; - double maxRayLength = std::sqrt(width2 * width2 + height2 * height2); - if(rayLength > maxRayLength) rayLength = maxRayLength; + double rayLength = zoom * radarRayLength; + double maxRayLength = std::sqrt(width2 * width2 + height2 * height2); + if(rayLength > maxRayLength) rayLength = maxRayLength; - int radarLineX = int(width2 + rayLength * std::cos(radarAngle)); - int radarLineY = int(height2 - rayLength * std::sin(radarAngle)); - gcdc.DrawLine(width2, height2, radarLineX, radarLineY); + int radarLineX = int(width2 + rayLength * std::cos(radarAngle)); + int radarLineY = int(height2 - rayLength * std::sin(radarAngle)); + graphicsContext.DrawLine(width2, height2, radarLineX, radarLineY); - drawRadarGradient(dc, width2, height2); + drawRadarGradient(paintContext, width2, height2); - radarMutex.unlock(); + radarMutex.unlock(); - controllerMutex.lock(); + controllerMutex.lock(); - dc.SetPen(*wxThePenList->FindOrCreatePen(pointColor)); - for(const regilo::ScanRecord& record : data) - { - if(record.error) continue; + paintContext.SetPen(*wxThePenList->FindOrCreatePen(pointColor)); + for(const regilo::ScanRecord& record : data) + { + if(record.error) continue; - double distance = record.distance * zoom; - int x = int(width2 + distance * std::cos(record.angle)); - int y = int(height2 - distance * std::sin(record.angle)); + double distance = record.distance * zoom; + int pointX = int(width2 + distance * std::cos(record.angle)); + int pointY = int(height2 - distance * std::sin(record.angle)); - dc.DrawRectangle(x, y, 2, 2); - } + paintContext.DrawRectangle(pointX, pointY, 2, 2); + } - controllerMutex.unlock(); + controllerMutex.unlock(); } void RegiloVisual::stopScanThread() { - if(scanThreadRunning) - { - scanThreadRunning = false; - scanThreadCV.notify_one(); - radarThreadCV.notify_one(); - } + if(scanThreadRunning) + { + scanThreadRunning = false; + scanThreadCV.notify_one(); + radarThreadCV.notify_one(); + } } void RegiloVisual::scanAndShow() { - controllerMutex.lock(); + controllerMutex.lock(); - data = controller->getScan(useScanner); - bool emptyData = data.empty(); - if(emptyData) stopScanThread(); + data = controller->getScan(useScanner); + bool emptyData = data.empty(); + if(emptyData) stopScanThread(); - controllerMutex.unlock(); + controllerMutex.unlock(); - this->GetTopWindow()->GetEventHandler()->CallAfter([this, emptyData] () - { - if(emptyData) setStatusText("No more scans to show (EOF).", 0); - else frame->Refresh(); - }); + this->GetTopWindow()->GetEventHandler()->CallAfter([this, emptyData] () + { + if(emptyData) setStatusText("No more scans to show (EOF).", 0); + else frame->Refresh(); + }); } -void RegiloVisual::setStatusText(const std::string& text, int i) +void RegiloVisual::setStatusText(const std::string& text, int number) { - frame->SetStatusText(text, i); - if(i == 1) refreshStatusBar(); + frame->SetStatusText(text, number); + if(number == 1) refreshStatusBar(); } void RegiloVisual::refreshStatusBar() { - wxStatusBar *statusBar = frame->GetStatusBar(); + wxStatusBar *statusBar = frame->GetStatusBar(); - int lastWidth = statusBar->GetTextExtent(statusBar->GetStatusText(1)).GetWidth() + 10; - if(lastWidth > 400) lastWidth = 400; + int lastWidth = statusBar->GetTextExtent(statusBar->GetStatusText(1)).GetWidth() + 10; + if(lastWidth > 400) lastWidth = 400; - const int statusBarWidths[] = { -1, lastWidth }; - statusBar->SetStatusWidths(2, statusBarWidths); + const int statusBarWidths[] = { -1, lastWidth }; + statusBar->SetStatusWidths(2, statusBarWidths); } void RegiloVisual::Display(wxApp *app, int& argc, char **argv) { - wxApp::SetInstance(app); - wxEntryStart(argc, argv); - app->CallOnInit(); - app->OnRun(); - app->OnExit(); - wxEntryCleanup(); + wxApp::SetInstance(app); + wxEntryStart(argc, argv); + app->CallOnInit(); + app->OnRun(); + app->OnExit(); + wxEntryCleanup(); } diff --git a/include/regilo/controller.hpp b/include/regilo/controller.hpp index cfcde27..7fa60b6 100644 --- a/include/regilo/controller.hpp +++ b/include/regilo/controller.hpp @@ -34,53 +34,53 @@ namespace regilo { class IController { public: - /** - * @brief Default destructor. - */ - virtual ~IController() = default; + /** + * @brief Default destructor. + */ + virtual ~IController() = default; - /** - * @brief Connect the controller to a device. - * @param endpoint The device endpoint (a path, IP address, etc.). - */ - virtual void connect(const std::string& endpoint) = 0; + /** + * @brief Connect the controller to a device. + * @param endpoint The device endpoint (a path, IP address, etc.). + */ + virtual void connect(const std::string& endpoint) = 0; - /** - * @brief Test if the controller is connected. - * @return True if connected. - */ - virtual bool isConnected() const = 0; + /** + * @brief Test if the controller is connected. + * @return True if connected. + */ + virtual bool isConnected() const = 0; - /** - * @brief Get the endpoint of device. - * @return The device endpoint or empty string. - */ - virtual std::string getEndpoint() const = 0; + /** + * @brief Get the endpoint of device. + * @return The device endpoint or empty string. + */ + virtual std::string getEndpoint() const = 0; - /** - * @brief Get the current Log. - * @return The Log or empty std::shared_ptr. - */ - virtual std::shared_ptr getLog() = 0; + /** + * @brief Get the current Log. + * @return The Log or empty std::shared_ptr. + */ + virtual std::shared_ptr getLog() = 0; - /** - * @brief Get the current Log (a const variant). - * @return The Log or empty std::shared_ptr. - */ - virtual std::shared_ptr getLog() const = 0; + /** + * @brief Get the current Log (a const variant). + * @return The Log or empty std::shared_ptr. + */ + virtual std::shared_ptr getLog() const = 0; - /** - * @brief Set a Log (it can be shared between more controllers). - * @param log Smart pointer to the Log. - */ - virtual void setLog(std::shared_ptr log) = 0; + /** + * @brief Set a Log (it can be shared between more controllers). + * @param log Smart pointer to the Log. + */ + virtual void setLog(std::shared_ptr log) = 0; - /** - * @brief Send a command to the device. - * @param command A command with all parameters. - * @return A string with a whole response to the command. - */ - virtual std::string sendCommand(const std::string& command) = 0; + /** + * @brief Send a command to the device. + * @param command A command with all parameters. + * @return A string with a whole response to the command. + */ + virtual std::string sendCommand(const std::string& command) = 0; }; } diff --git a/include/regilo/hokuyocontroller.hpp b/include/regilo/hokuyocontroller.hpp index 7715d29..d1836a4 100644 --- a/include/regilo/hokuyocontroller.hpp +++ b/include/regilo/hokuyocontroller.hpp @@ -39,16 +39,16 @@ namespace regilo { class IHokuyoController : public virtual IScanController { public: - /** - * @brief Default destructor. - */ - virtual ~IHokuyoController() = default; - - /** - * @brief Return information about the scanner version. - * @return Key-value pairs with the information. - */ - virtual std::map getVersionInfo() = 0; + /** + * @brief Default destructor. + */ + virtual ~IHokuyoController() = default; + + /** + * @brief Return information about the scanner version. + * @return Key-value pairs with the information. + */ + virtual std::map getVersionInfo() = 0; }; /** @@ -58,53 +58,57 @@ template class HokuyoController : public IHokuyoController, public ScanController { private: - std::size_t validFromStep = 44; - std::size_t validToStep = 725; - std::size_t maxStep = 768; - std::size_t fromStep = 0; - std::size_t toStep = maxStep; - std::size_t clusterCount = 1; - double startAngle = -135 * M_PI / 180; + std::size_t validFromStep = 44; + std::size_t validToStep = 725; + std::size_t maxStep = 768; + std::size_t fromStep = 0; + std::size_t toStep = maxStep; + std::size_t clusterCount = 1; + double startAngle = -135 * M_PI / 180; protected: - virtual inline std::string getScanCommand() const override { return this->createFormattedCommand(CMD_GET_SCAN, fromStep, toStep, clusterCount); } - virtual bool parseScanData(std::istream& in, ScanData& data) override; + virtual inline std::string getScanCommand() const override + { + return this->createFormattedCommand(CMD_GET_SCAN, fromStep, toStep, clusterCount); + } + + virtual bool parseScanData(std::istream& input, ScanData& data) override; public: - static std::string CMD_GET_VERSION; ///< A command for getting the scanner version. - static std::string CMD_GET_SCAN; ///< A command for getting a scan. - - /** - * @brief Default constructor. - */ - HokuyoController(); - - /** - * @brief Constructor with a log file specified by a path. - * @param logPath Path to the log file. - */ - HokuyoController(const std::string& logPath); - - /** - * @brief Constructor with a log specified by a stream. - * @param logStream The log stream. - */ - HokuyoController(std::iostream& logStream); - - /** - * @brief Default destructor. - */ - virtual ~HokuyoController() = default; - - virtual std::map getVersionInfo() override; - - /** - * @brief Set parameters for the scan command. - * @param fromStep The starting step [0; maxStep]. - * @param toStep The ending steop [0; maxStep]. - * @param clusterCount The cluster count [0; 99]. - */ - void setScanParameters(std::size_t fromStep, std::size_t toStep, std::size_t clusterCount); + static std::string CMD_GET_VERSION; ///< A command for getting the scanner version. + static std::string CMD_GET_SCAN; ///< A command for getting a scan. + + /** + * @brief Default constructor. + */ + HokuyoController(); + + /** + * @brief Constructor with a log file specified by a path. + * @param logPath Path to the log file. + */ + HokuyoController(const std::string& logPath); + + /** + * @brief Constructor with a log specified by a stream. + * @param logStream The log stream. + */ + HokuyoController(std::iostream& logStream); + + /** + * @brief Default destructor. + */ + virtual ~HokuyoController() = default; + + virtual std::map getVersionInfo() override; + + /** + * @brief Set parameters for the scan command. + * @param fromStep The starting step [0; maxStep]. + * @param toStep The ending steop [0; maxStep]. + * @param clusterCount The cluster count [0; 99]. + */ + void setScanParameters(std::size_t fromStep, std::size_t toStep, std::size_t clusterCount); }; extern template class HokuyoController; @@ -122,97 +126,103 @@ std::string HokuyoController::CMD_GET_SCAN = "G%03d%03d%02d" template HokuyoController::HokuyoController() : ScanController() { - this->RESPONSE_END = "\n\n"; + this->RESPONSE_END = "\n\n"; } template -HokuyoController::HokuyoController(const std::string& logPath) : ScanController(logPath) +HokuyoController::HokuyoController(const std::string& logPath) : + ScanController(logPath) { - this->RESPONSE_END = "\n\n"; + this->RESPONSE_END = "\n\n"; } template -HokuyoController::HokuyoController(std::iostream& logStream) : ScanController(logStream) +HokuyoController::HokuyoController(std::iostream& logStream) : + ScanController(logStream) { - this->RESPONSE_END = "\n\n"; + this->RESPONSE_END = "\n\n"; } template std::map HokuyoController::getVersionInfo() { - std::map versionInfo; + if(ProtocolController::template sendCommand(CMD_GET_VERSION) != '0') + { + return std::map(); + } + + std::map versionInfo; + std::string line; - if(ProtocolController::template sendCommand(CMD_GET_VERSION) == '0') - { - std::string line; - while(std::getline(this->deviceOutput, line)) - { - if(line.empty()) continue; + while(std::getline(this->deviceOutput, line)) + { + if(line.empty()) continue; - std::size_t colonPos = line.find(':'); - std::string name = line.substr(0, colonPos); - std::string value = line.substr(colonPos + 1); + std::size_t colonPos = line.find(':'); + std::string name = line.substr(0, colonPos); + std::string value = line.substr(colonPos + 1); - boost::algorithm::trim(name); - boost::algorithm::trim(value); + boost::algorithm::trim(name); + boost::algorithm::trim(value); - versionInfo[name] = value; - } - } + versionInfo[name] = value; + } - return versionInfo; + return versionInfo; } template -void HokuyoController::setScanParameters(std::size_t fromStep, std::size_t toStep, std::size_t clusterCount) +void HokuyoController::setScanParameters( + std::size_t fromStep, std::size_t toStep, std::size_t clusterCount +) { - if(fromStep > maxStep) throw std::invalid_argument("Invalid fromStep argument."); - if(toStep > maxStep) throw std::invalid_argument("Invalid fromStep argument."); - if(clusterCount > 99) throw std::invalid_argument("Invalid clusterCount argument."); - if(fromStep > toStep) throw std::invalid_argument("fromStep has to be lower than toStep."); - - this->fromStep = fromStep; - this->toStep = toStep; - this->clusterCount = clusterCount; + if(fromStep > maxStep) throw std::invalid_argument("Invalid fromStep argument."); + if(toStep > maxStep) throw std::invalid_argument("Invalid fromStep argument."); + if(clusterCount > 99) throw std::invalid_argument("Invalid clusterCount argument."); + if(fromStep > toStep) throw std::invalid_argument("fromStep has to be lower than toStep."); + + this->fromStep = fromStep; + this->toStep = toStep; + this->clusterCount = clusterCount; } template -bool HokuyoController::parseScanData(std::istream& in, ScanData& data) +bool HokuyoController::parseScanData(std::istream& input, ScanData& data) { - char status; - in >> status; - if(status != '0') return false; + char status; + input >> status; + if(status != '0') return false; - double resolution = M_PI / 512; + double resolution = M_PI / 512; - int lastId = 0; - std::size_t step = fromStep - 1; - while(in) - { - step++; + int lastIndex = 0; + std::size_t step = fromStep - 1; + while(input) + { + step++; - char high, low; - in >> high >> low; + char high, low; + input >> high >> low; - if(step < validFromStep || step > validToStep) continue; + if(step < validFromStep || step > validToStep) continue; - int id = lastId++; - double angle = step * resolution + startAngle; - int distance = ((high - '0') << 6) | (low - '0'); - int errorCode = 0; - bool error = false; + int index = lastIndex++; + double angle = step * resolution + startAngle; + int distance = ((high - '0') << 6) | (low - '0'); + int errorCode = 0; + bool error = false; - if(distance < 20) - { - errorCode = distance; - distance = -1; - error = true; - } + if(distance < 20) + { + errorCode = distance; + distance = -1; + error = true; + } - data.emplace_back(id, angle, distance, -1, errorCode, error); - } + data.emplace_back(index, angle, distance, -1, errorCode, error); + } - return true; + return true; } } diff --git a/include/regilo/log.hpp b/include/regilo/log.hpp index a3c604e..b5af474 100644 --- a/include/regilo/log.hpp +++ b/include/regilo/log.hpp @@ -32,16 +32,16 @@ namespace regilo { /** * @brief The InvalidLogException is thrown when the data stream contains - * a value that is not expected. + * a value that is not expected. */ class InvalidLogException : public std::runtime_error { public: - /** - * @brief The default constructor. - * @param message A string that is printed. - */ - InvalidLogException(const std::string& message); + /** + * @brief The default constructor. + * @param message A string that is printed. + */ + InvalidLogException(const std::string& message); }; /** @@ -50,41 +50,41 @@ class InvalidLogException : public std::runtime_error class LogMetadata { private: - std::string type = "log"; - int version = 2; + std::string type = "log"; + int version = 2; protected: - /** - * @brief The default constructor is available only in derived and friend classes. - */ - LogMetadata() = default; - - /** - * @brief This constructor is available only in derived and friend classes. - * @param type A log type. - * @param version A log version. - */ - LogMetadata(const std::string& type, int version); + /** + * @brief The default constructor is available only in derived and friend classes. + */ + LogMetadata() = default; + + /** + * @brief This constructor is available only in derived and friend classes. + * @param type A log type. + * @param version A log version. + */ + LogMetadata(const std::string& type, int version); public: - /** - * @brief The default destructor. - */ - virtual ~LogMetadata() = default; - - /** - * @brief Get the log type. - * @return A string with the type. - */ - inline virtual const std::string& getType() const final { return type; } - - /** - * @brief Get the log version. - * @return The version number. - */ - inline virtual int getVersion() const final { return version; } - - friend class Log; + /** + * @brief The default destructor. + */ + virtual ~LogMetadata() = default; + + /** + * @brief Get the log type. + * @return A string with the type. + */ + inline virtual const std::string& getType() const final { return type; } + + /** + * @brief Get the log version. + * @return The version number. + */ + inline virtual int getVersion() const final { return version; } + + friend class Log; }; /** @@ -93,214 +93,214 @@ class LogMetadata class ILog { public: - /** - * @brief Default destructor. - */ - virtual ~ILog() = default; - - /** - * @brief Get the path of file if the log was created with a path otherwise the empty string. - * @return The path or empty string. - */ - virtual const std::string& getFilePath() const = 0; - - /** - * @brief Get the current underlying stream. - * @return The underlying stream. - */ - virtual std::iostream& getStream() = 0; - - /** - * @brief Test if the stream is EOF. - * @return True if the log is in the EOF state. - */ - virtual bool isEnd() const = 0; - - /** - * @brief Read the metadata. It is usefull to determinate the metadata in runtime. - */ - virtual void readMetadata() = 0; - - /** - * @brief Get the associated metadata. - * @return A pointer to metadata - */ - virtual const LogMetadata* getMetadata() const = 0; - - /** - * @brief Read one command from the log. - * @return The response of the command. - */ - virtual std::string read() = 0; - - /** - * @brief Read one command from the log. - * @param logCommand The input of the command that was read. - * @return The response of the command. - */ - virtual std::string read(std::string& logCommand) = 0; - - /** - * @brief Read specified command from the log (the others are skipped). - * @param command The command to read (The boost::algorithm::starts_with() method is used to compare). - * @return The response of the command. - */ - virtual std::string readCommand(const std::string& command) = 0; - - /** - * @brief Read specified command from the log (the others are skipped). - * @param command The command to read (The boost::algorithm::starts_with() method is used to compare). - * @param logCommand The input of the command that was read. - * @return The response of the command. - */ - virtual std::string readCommand(const std::string& command, std::string& logCommand) = 0; - - /** - * @brief Write a command and response to the log. - * @param command The command (with all parameters). - * @param response The response of the command. - */ - virtual void write(const std::string& command, const std::string& response) = 0; - - /** - * @brief Close the log file. - */ - virtual void close() = 0; + /** + * @brief Default destructor. + */ + virtual ~ILog() = default; + + /** + * @brief Get the path of file if the log was created with a path otherwise the empty string. + * @return The path or empty string. + */ + virtual const std::string& getFilePath() const = 0; + + /** + * @brief Get the current underlying stream. + * @return The underlying stream. + */ + virtual std::iostream& getStream() = 0; + + /** + * @brief Test if the stream is EOF. + * @return True if the log is in the EOF state. + */ + virtual bool isEnd() const = 0; + + /** + * @brief Read the metadata. It is usefull to determinate the metadata in runtime. + */ + virtual void readMetadata() = 0; + + /** + * @brief Get the associated metadata. + * @return A pointer to metadata + */ + virtual const LogMetadata* getMetadata() const = 0; + + /** + * @brief Read one command from the log. + * @return The response of the command. + */ + virtual std::string read() = 0; + + /** + * @brief Read one command from the log. + * @param logCommand The input of the command that was read. + * @return The response of the command. + */ + virtual std::string read(std::string& logCommand) = 0; + + /** + * @brief Read specified command from the log (the others are skipped). + * @param command The command to read (The boost::algorithm::starts_with() method is used to compare). + * @return The response of the command. + */ + virtual std::string readCommand(const std::string& command) = 0; + + /** + * @brief Read specified command from the log (the others are skipped). + * @param command The command to read (The boost::algorithm::starts_with() method is used to compare). + * @param logCommand The input of the command that was read. + * @return The response of the command. + */ + virtual std::string readCommand(const std::string& command, std::string& logCommand) = 0; + + /** + * @brief Write a command and response to the log. + * @param command The command (with all parameters). + * @param response The response of the command. + */ + virtual void write(const std::string& command, const std::string& response) = 0; + + /** + * @brief Close the log file. + */ + virtual void close() = 0; }; /** * @brief The Log class is a basic log with a simple read/write functionality. - * It is used to log all commands that were send to the device. + * It is used to log all commands that were send to the device. */ class Log : public virtual ILog { private: - std::string filePath; - std::fstream *fileStream; + std::string filePath; + std::fstream *fileStream; - std::mutex streamMutex; + std::mutex streamMutex; - bool metadataRead = false; - bool metadataWritten = false; + bool metadataRead = false; + bool metadataWritten = false; protected: - std::iostream& stream; ///< The underlying stream. - LogMetadata *metadata = nullptr; ///< The metadata object. - - /** - * @brief Read the next char and check if it matches. - * - * Read the next char and check if it matches with the name. If not - * an exception is thrown. - * - * @param stream A stream that is used for reading. - * @param name A char that is used to check. - */ - void readName(std::istream& stream, char name); - - /** - * @brief Read the next string and check if it matches. - * - * Read the next string and check if it matches with the name. If not - * an exception is thrown. - * - * @param stream A stream that is used for reading. - * @param name A string that is used to check. - */ - void readName(std::istream& stream, const std::string& name); - - /** - * @brief Read the next value that is specified with a length. - * @param stream A stream that is used for reading. - * @return The value. - */ - std::string readValue(std::istream& stream); - - /** - * @brief Read the next char and value that is specified with a length. - * - * Read the next char and value that is specified with a length and check - * if the char matches with the name. If not an exception is thrown. - * - * @param stream A stream that is used for reading. - * @param name A char that is used to check. - * @return The value. - */ - std::string readNameValue(std::istream& stream, char name); - - /** - * @brief Read the next char and value that is specified with a length. - * - * Read the next char and value that is specified with a length and check - * if the char matches with the name. If not an exception is thrown. - * - * @param stream A stream that is used for reading. - * @param name A string that is used to check. - * @return The value. - */ - std::string readNameValue(std::istream& stream, const std::string& name); - - /** - * @brief Read metadata from the log. - * @param metaStream A stream that is used for reading. - */ - virtual void readMetadata(std::istream& metaStream); - - /** - * @brief Write metadata to the log. - * @param metaStream A stream that is used for writing. - */ - virtual void writeMetadata(std::ostream& metaStream); - - /** - * @brief Read a command and response from the log. - * This method can be safely overridden. - * @param logCommand The input of the command that was read. - * @return The response of the command. - */ - virtual std::string readData(std::string& logCommand); - - /** - * @brief Write a command and response to the log. - * This method can be safely overridden. - * @param command The command (with all parameters). - * @param response The response of the command. - */ - virtual void writeData(const std::string& command, const std::string& response); + std::iostream& stream; ///< The underlying stream. + LogMetadata *metadata = nullptr; ///< The metadata object. + + /** + * @brief Read the next char and check if it matches. + * + * Read the next char and check if it matches with the name. If not + * an exception is thrown. + * + * @param stream A stream that is used for reading. + * @param name A char that is used to check. + */ + void readName(std::istream& stream, char name); + + /** + * @brief Read the next string and check if it matches. + * + * Read the next string and check if it matches with the name. If not + * an exception is thrown. + * + * @param stream A stream that is used for reading. + * @param name A string that is used to check. + */ + void readName(std::istream& stream, const std::string& name); + + /** + * @brief Read the next value that is specified with a length. + * @param stream A stream that is used for reading. + * @return The value. + */ + std::string readValue(std::istream& stream); + + /** + * @brief Read the next char and value that is specified with a length. + * + * Read the next char and value that is specified with a length and check + * if the char matches with the name. If not an exception is thrown. + * + * @param stream A stream that is used for reading. + * @param name A char that is used to check. + * @return The value. + */ + std::string readNameValue(std::istream& stream, char name); + + /** + * @brief Read the next char and value that is specified with a length. + * + * Read the next char and value that is specified with a length and check + * if the char matches with the name. If not an exception is thrown. + * + * @param stream A stream that is used for reading. + * @param name A string that is used to check. + * @return The value. + */ + std::string readNameValue(std::istream& stream, const std::string& name); + + /** + * @brief Read metadata from the log. + * @param metaStream A stream that is used for reading. + */ + virtual void readMetadata(std::istream& metaStream); + + /** + * @brief Write metadata to the log. + * @param metaStream A stream that is used for writing. + */ + virtual void writeMetadata(std::ostream& metaStream); + + /** + * @brief Read a command and response from the log. + * This method can be safely overridden. + * @param logCommand The input of the command that was read. + * @return The response of the command. + */ + virtual std::string readData(std::string& logCommand); + + /** + * @brief Write a command and response to the log. + * This method can be safely overridden. + * @param command The command (with all parameters). + * @param response The response of the command. + */ + virtual void writeData(const std::string& command, const std::string& response); public: - /** - * @brief Log constructor with logging to a file. - * @param filePath The path of file. - */ - Log(const std::string& filePath); - - /** - * @brief Log constructor with logging to a stream. - * @param stream Input/output stream. - */ - Log(std::iostream& stream); - - /** - * @brief Default destructor. - */ - virtual ~Log(); - - virtual inline const std::string& getFilePath() const override { return filePath; } - virtual inline std::iostream& getStream() override { return stream; } - virtual inline bool isEnd() const override { return !stream; } - - virtual void readMetadata() override final; - virtual inline const LogMetadata* getMetadata() const override { return metadata; } - - virtual std::string read() override final; - virtual std::string read(std::string& logCommand) override final; - virtual std::string readCommand(const std::string& command) override final; - virtual std::string readCommand(const std::string& command, std::string& logCommand) override final; - - virtual void write(const std::string& command, const std::string& response) override final; - - virtual void close() override; + /** + * @brief Log constructor with logging to a file. + * @param filePath The path of file. + */ + Log(const std::string& filePath); + + /** + * @brief Log constructor with logging to a stream. + * @param stream Input/output stream. + */ + Log(std::iostream& stream); + + /** + * @brief Default destructor. + */ + virtual ~Log(); + + virtual inline const std::string& getFilePath() const override { return filePath; } + virtual inline std::iostream& getStream() override { return stream; } + virtual inline bool isEnd() const override { return !stream; } + + virtual void readMetadata() override final; + virtual inline const LogMetadata* getMetadata() const override { return metadata; } + + virtual std::string read() override final; + virtual std::string read(std::string& logCommand) override final; + virtual std::string readCommand(const std::string& command) override final; + virtual std::string readCommand(const std::string& command, std::string& logCommand) override final; + + virtual void write(const std::string& command, const std::string& response) override final; + + virtual void close() override; }; } diff --git a/include/regilo/neatocontroller.hpp b/include/regilo/neatocontroller.hpp index 244ebac..e5e37d7 100644 --- a/include/regilo/neatocontroller.hpp +++ b/include/regilo/neatocontroller.hpp @@ -32,54 +32,67 @@ namespace regilo { +namespace balg = boost::algorithm; + /** * @brief The INeatoController interface is used for the NeatoController class. */ class INeatoController : public virtual IScanController { public: - /** - * @brief Default destructor. - */ - virtual ~INeatoController() = default; - - /** - * @brief Get whether the Neato is in the test mode. - * @return True if the Neato is in the test mode. - */ - virtual bool getTestMode() const = 0; - - /** - * @brief Set or unset the test mode. - * @param testMode True for setting the test mode. - */ - virtual void setTestMode(bool testMode) = 0; - - /** - * @brief Get whether the Neato has LDS rotation on or off. - * @return True if the LIDAR is rotating. - */ - virtual bool getLdsRotation() const = 0; - - /** - * @brief Set LDS rotation on or off. - * @param ldsRotation True for starting the LIDAR rotation. - */ - virtual void setLdsRotation(bool ldsRotation) = 0; - - /** - * @brief Set the specified motor to run in a direction at a requested speed. - * @param left Distance in millimeters to drive the left wheel (pos = forward, neg = backward). - * @param right Distance in millimeters to drive the right wheel (pos = forward, neg = backward). - * @param speed Speed in millimeters/second. - */ - virtual void setMotor(int left, int right, int speed) = 0; - - /** - * @brief Get the current scheduler time. - * @return "DayOfWeek HourOf24:Min:Sec" (example: "Sunday 13:57:09"). - */ - virtual std::string getTime() = 0; + /** + * @brief Default destructor. + */ + virtual ~INeatoController() = default; + + /** + * @brief Get whether the Neato is in the test mode. + * @return True if the Neato is in the test mode. + */ + virtual bool getTestMode() const = 0; + + /** + * @brief Set or unset the test mode. + * @param testMode True for setting the test mode. + */ + virtual void setTestMode(bool testMode) = 0; + + /** + * @brief Get whether the Neato has LDS rotation on or off. + * @return True if the LIDAR is rotating. + */ + virtual bool getLdsRotation() const = 0; + + /** + * @brief Set LDS rotation on or off. + * @param ldsRotation True for starting the LIDAR rotation. + */ + virtual void setLdsRotation(bool ldsRotation) = 0; + + /** + * @brief Start the scanner by turning on the test mode and LDS rotation. + */ + virtual void startScanner() = 0; + + /** + * @brief Stop the scanner by turning off the test mode and LDS rotation. + */ + virtual void stopScanner() = 0; + + /** + * @brief Set the specified motor to run in a direction at a requested speed. + * @param left Distance in millimeters to drive the left wheel (pos = forward, neg = backward). + * @param right Distance in millimeters to drive the right wheel (pos = forward, + * neg = backward). + * @param speed Speed in millimeters/second. + */ + virtual void setMotor(int left, int right, int speed) = 0; + + /** + * @brief Get the current scheduler time. + * @return "DayOfWeek HourOf24:Min:Sec" (example: "Sunday 13:57:09"). + */ + virtual std::string getTime() = 0; }; /** @@ -89,58 +102,62 @@ template class NeatoController : public INeatoController, public ScanController { private: - bool testMode = false; - bool ldsRotation = false; + bool testMode = false; + bool ldsRotation = false; protected: - virtual inline std::string getScanCommand() const override { return CMD_GET_LDS_SCAN; } - virtual bool parseScanData(std::istream& in, ScanData& data) override; + virtual inline std::string getScanCommand() const override { return CMD_GET_LDS_SCAN; } + virtual bool parseScanData(std::istream& input, ScanData& data) override; public: - static std::string ON; ///< A string that represents the ON value. - static std::string OFF; ///< A string that represents the OFF value. - static std::string LDS_SCAN_HEADER; ///< A header of the LDS scan output. - static std::string LDS_SCAN_FOOTER; ///< A footer of the LDS scan output. + static std::string ON_VALUE; ///< A string that represents the ON value. + static std::string OFF_VALUE; ///< A string that represents the OFF value. + static std::string LDS_SCAN_HEADER; ///< A header of the LDS scan output. + static std::string LDS_SCAN_FOOTER; ///< A footer of the LDS scan output. + + static std::string CMD_TEST_MODE; ///< A template for the `testmode` command. + static std::string CMD_SET_LDS_ROTATION; ///< A template for the `setldsrotation` command. + static std::string CMD_SET_MOTOR; ///< A template for the `setmotor` command. + static std::string CMD_GET_TIME; ///< A template for the `gettime` command. + static std::string CMD_GET_LDS_SCAN; ///< A template for the `getldsscan` command. + + /** + * @brief Default constructor. + */ + NeatoController(); - static std::string CMD_TEST_MODE; ///< A template for the `testmode` command. - static std::string CMD_SET_LDS_ROTATION; ///< A template for the `setldsrotation` command. - static std::string CMD_SET_MOTOR; ///< A template for the `setmotor` command. - static std::string CMD_GET_TIME; ///< A template for the `gettime` command. - static std::string CMD_GET_LDS_SCAN; ///< A template for the `getldsscan` command. + /** + * @brief Constructor with a log file specified by a path. + * @param logPath Path to the log file. + */ + NeatoController(const std::string& logPath); - /** - * @brief Default constructor. - */ - NeatoController(); + /** + * @brief Constructor with a log specified by a stream. + * @param logStream The log stream. + */ + NeatoController(std::iostream& logStream); - /** - * @brief Constructor with a log file specified by a path. - * @param logPath Path to the log file. - */ - NeatoController(const std::string& logPath); + /** + * @brief Default destructor. + */ + virtual ~NeatoController() = default; - /** - * @brief Constructor with a log specified by a stream. - * @param logStream The log stream. - */ - NeatoController(std::iostream& logStream); + virtual inline bool getTestMode() const override { return testMode; } - /** - * @brief Default destructor. - */ - virtual ~NeatoController() = default; + virtual void setTestMode(bool testMode) override; - virtual inline bool getTestMode() const override { return testMode; } + virtual inline bool getLdsRotation() const override { return ldsRotation; } - virtual void setTestMode(bool testMode) override; + virtual void setLdsRotation(bool ldsRotation) override; - virtual inline bool getLdsRotation() const override { return ldsRotation; } + virtual void startScanner() override; - virtual void setLdsRotation(bool ldsRotation) override; + virtual void stopScanner() override; - virtual void setMotor(int left, int right, int speed) override; + virtual void setMotor(int left, int right, int speed) override; - virtual std::string getTime() override; + virtual std::string getTime() override; }; extern template class NeatoController; @@ -150,13 +167,14 @@ typedef NeatoController NeatoSerialController; typedef NeatoController NeatoSocketController; template -std::string NeatoController::ON = "on"; +std::string NeatoController::ON_VALUE = "on"; template -std::string NeatoController::OFF = "off"; +std::string NeatoController::OFF_VALUE = "off"; template -std::string NeatoController::LDS_SCAN_HEADER = "AngleInDegrees,DistInMM,Intensity,ErrorCodeHEX"; +std::string NeatoController::LDS_SCAN_HEADER = + "AngleInDegrees,DistInMM,Intensity,ErrorCodeHEX"; template std::string NeatoController::LDS_SCAN_FOOTER = "ROTATION_SPEED,"; @@ -179,94 +197,110 @@ std::string NeatoController::CMD_GET_LDS_SCAN = "getldsscan" template NeatoController::NeatoController() : ScanController() { - this->RESPONSE_END = std::string(1, 0x1a); + this->RESPONSE_END = std::string(1, 0x1a); } template -NeatoController::NeatoController(const std::string& logPath) : ScanController(logPath) +NeatoController::NeatoController(const std::string& logPath) : + ScanController(logPath) { - this->RESPONSE_END = std::string(1, 0x1a); + this->RESPONSE_END = std::string(1, 0x1a); } template -NeatoController::NeatoController(std::iostream& logStream) : ScanController(logStream) +NeatoController::NeatoController(std::iostream& logStream) : + ScanController(logStream) { - this->RESPONSE_END = std::string(1, 0x1a); + this->RESPONSE_END = std::string(1, 0x1a); } template void NeatoController::setTestMode(bool testMode) { - this->sendFormattedCommand(CMD_TEST_MODE, (testMode ? ON : OFF).c_str()); - this->testMode = testMode; + this->sendFormattedCommand(CMD_TEST_MODE, (testMode ? ON_VALUE : OFF_VALUE).c_str()); + this->testMode = testMode; } template void NeatoController::setLdsRotation(bool ldsRotation) { - this->sendFormattedCommand(CMD_SET_LDS_ROTATION, (ldsRotation ? ON : OFF).c_str()); - this->ldsRotation = ldsRotation; + this->sendFormattedCommand(CMD_SET_LDS_ROTATION, (ldsRotation ? ON_VALUE : OFF_VALUE).c_str()); + this->ldsRotation = ldsRotation; +} + +template +void NeatoController::startScanner() +{ + setTestMode(true); + setLdsRotation(true); +} + +template +void NeatoController::stopScanner() +{ + setLdsRotation(false); + setTestMode(false); } template void NeatoController::setMotor(int left, int right, int speed) { - this->sendFormattedCommand(CMD_SET_MOTOR, left, right, speed); + this->sendFormattedCommand(CMD_SET_MOTOR, left, right, speed); } template -bool NeatoController::parseScanData(std::istream& in, ScanData& data) +bool NeatoController::parseScanData(std::istream& input, ScanData& data) { - int lastId = 0; - double M_PI_180 = M_PI / 180.0; - - std::string line; - std::getline(in, line); - boost::algorithm::trim(line); - - if(line == NeatoController::LDS_SCAN_HEADER) - { - while(true) - { - std::getline(in, line); - boost::algorithm::trim(line); - - if(boost::algorithm::starts_with(line, NeatoController::LDS_SCAN_FOOTER)) - { - std::vector values; - boost::algorithm::split(values, line, boost::algorithm::is_any_of(",")); - data.rotationSpeed = std::stod(values.at(1)); - - break; - } - else - { - std::vector values; - boost::algorithm::split(values, line, boost::algorithm::is_any_of(",")); - - int id = lastId++; - double angle = std::stod(values.at(0)) * M_PI_180; - double distance = std::stod(values.at(1)); - int intensity = std::stoi(values.at(2)); - int errorCode = std::stoi(values.at(3)); - bool error = (errorCode != 0); - - if(error) distance = -1; - - data.emplace_back(id, angle, distance, intensity, errorCode, error); - } - } - - return true; - } - - return false; + int lastIndex = 0; + double M_PI_180 = M_PI / 180.0; + + std::string line; + std::getline(input, line); + balg::trim(line); + + if(line != NeatoController::LDS_SCAN_HEADER) + { + return false; + } + + while(true) + { + std::getline(input, line); + balg::trim(line); + + if(balg::starts_with(line, NeatoController::LDS_SCAN_FOOTER)) + { + std::vector values; + balg::split(values, line, balg::is_any_of(",")); + data.rotationSpeed = std::stod(values.at(1)); + + break; + } + else + { + std::vector values; + balg::split(values, line, balg::is_any_of(",")); + + int index = lastIndex++; + double angle = std::stod(values.at(0)) * M_PI_180; + double distance = std::stod(values.at(1)); + int intensity = std::stoi(values.at(2)); + int errorCode = std::stoi(values.at(3)); + bool error = errorCode != 0; + + if(error) distance = -1; + + data.emplace_back(index, angle, distance, intensity, errorCode, error); + } + } + + return true; } template std::string NeatoController::getTime() { - return this->sendCommand(CMD_GET_TIME); + return this->sendCommand(CMD_GET_TIME); } } diff --git a/include/regilo/scancontroller.hpp b/include/regilo/scancontroller.hpp index f122104..c1dd7d2 100644 --- a/include/regilo/scancontroller.hpp +++ b/include/regilo/scancontroller.hpp @@ -35,17 +35,17 @@ namespace regilo { class IScanController : public virtual IController { public: - /** - * @brief Default destructor. - */ - virtual ~IScanController() = default; - - /** - * @brief Get a scan from the device. - * @param fromDevice Specify if you want to get a scan from the device (true) or log (false). Default: true. - * @return ScanData - */ - virtual ScanData getScan(bool fromDevice = true) = 0; + /** + * @brief Default destructor. + */ + virtual ~IScanController() = default; + + /** + * @brief Get a scan from the device. + * @param fromDevice Specify if you want to get a scan from the device (true) or log (false). Default: true. + * @return ScanData + */ + virtual ScanData getScan(bool fromDevice = true) = 0; }; /** @@ -55,58 +55,58 @@ template class ScanController : public virtual IScanController, public ProtocolController { protected: - std::size_t lastScanId = 0; ///< A scan id (starting from zero) that is used for new scans. - - /** - * @brief Get a string that can be used for getting a scan. - * @return A command for getting a scan. - */ - virtual std::string getScanCommand() const = 0; - - /** - * @brief Parse the raw scan data. - * @param in The input stream that stores the raw scan data. - * @param data Output for the scanned data. - * @return True if the parsing ends without an error. - */ - virtual bool parseScanData(std::istream& in, ScanData& data) = 0; + std::size_t lastScanIndex = 0; ///< A scan index (starting from zero) that is used for new scans. + + /** + * @brief Get a string that can be used for getting a scan. + * @return A command for getting a scan. + */ + virtual std::string getScanCommand() const = 0; + + /** + * @brief Parse the raw scan data. + * @param input The input stream that stores the raw scan data. + * @param data Output for the scanned data. + * @return True if the parsing ends without an error. + */ + virtual bool parseScanData(std::istream& input, ScanData& data) = 0; public: - using ProtocolController::ProtocolController; + using ProtocolController::ProtocolController; - /** - * @brief Default destructor. - */ - virtual ~ScanController() = default; + /** + * @brief Default destructor. + */ + virtual ~ScanController() = default; - virtual ScanData getScan(bool fromDevice = true) override final; + virtual ScanData getScan(bool fromDevice = true) override final; }; template ScanData ScanController::getScan(bool fromDevice) { - ScanData data; - - if(fromDevice) - { - ProtocolController::template sendCommand<>(getScanCommand()); - data.time = epoch().count(); - - parseScanData(this->deviceOutput, data); - } - else - { - std::istringstream response(this->log->readCommand(getScanCommand())); - if(std::shared_ptr timedLog = std::dynamic_pointer_cast(this->getLog())) - { - data.time = timedLog->getLastCommandTimeAs().count(); - } - - parseScanData(response, data); - } - if(!data.empty()) data.scanId = lastScanId++; - - return data; + ScanData data; + + if(fromDevice) + { + ProtocolController::template sendCommand<>(getScanCommand()); + data.time = epoch().count(); + + parseScanData(this->deviceOutput, data); + } + else + { + std::istringstream response(this->log->readCommand(getScanCommand())); + if(std::shared_ptr timedLog = std::dynamic_pointer_cast(this->getLog())) + { + data.time = timedLog->getLastCommandTimeAs().count(); + } + + parseScanData(response, data); + } + if(!data.empty()) data.index = lastScanIndex++; + + return data; } } diff --git a/include/regilo/scandata.hpp b/include/regilo/scandata.hpp index 92dc768..b160f95 100644 --- a/include/regilo/scandata.hpp +++ b/include/regilo/scandata.hpp @@ -34,26 +34,26 @@ namespace regilo { class ScanData : public std::vector { public: - std::size_t scanId = std::size_t(-1); ///< The scan id (starting from zero). - double rotationSpeed = -1; ///< The rotation speed (in Hz). - long time; ///< The scan time (milliseconds since epoch). - - /** - * @brief Default constructor. - */ - ScanData() = default; - - /** - * @brief Construct ScanData. - * @param scanId The scan id (starting from zero). - * @param rotationSpeed The rotation speed (in Hz). - */ - ScanData(std::size_t scanId, double rotationSpeed); - - /** - * @brief Output the data as a string. - */ - friend std::ostream& operator<<(std::ostream& out, const ScanData& record); + std::size_t index = std::size_t(-1); ///< The scan index (starting from zero). + double rotationSpeed = -1; ///< The rotation speed (in Hz). + long time; ///< The scan time (milliseconds since epoch). + + /** + * @brief Default constructor. + */ + ScanData() = default; + + /** + * @brief Construct ScanData. + * @param index The scan index (starting from zero). + * @param rotationSpeed The rotation speed (in Hz). + */ + ScanData(std::size_t index, double rotationSpeed); + + /** + * @brief Output the data as a string. + */ + friend std::ostream& operator<<(std::ostream& out, const ScanData& record); }; } diff --git a/include/regilo/scanrecord.hpp b/include/regilo/scanrecord.hpp index 36a3299..3e5fc1b 100644 --- a/include/regilo/scanrecord.hpp +++ b/include/regilo/scanrecord.hpp @@ -32,33 +32,33 @@ namespace regilo { class ScanRecord { public: - int id; ///< The id of the record (starting from zero). - double angle; ///< The angle of the record (in radians). - double distance; ///< The distance that was measured in the angle (in millimeters). - int intensity; ///< The normalized spot intensity that was measured in the angle. - int errorCode; ///< The error code. - bool error; ///< True if this record has an error. + int index; ///< The index of the record (starting from zero). + double angle; ///< The angle of the record (in radians). + double distance; ///< The distance that was measured in the angle (in millimeters). + int intensity; ///< The normalized spot intensity that was measured in the angle. + int errorCode; ///< The error code. + bool error; ///< True if this record has an error. - /** - * @brief Default constructor. - */ - ScanRecord() = default; + /** + * @brief Default constructor. + */ + ScanRecord() = default; - /** - * @brief Construct a ScanRecord from all attributes. - * @param id The id of the record (starting from zero). - * @param angle The angle of the record (in radians). - * @param distance The distance that was measured in the angle (in millimeters). - * @param intensity The normalized spot intensity that was measured in the angle. - * @param errorCode The error code. - * @param error True if this record has an error. - */ - ScanRecord(int id, double angle, double distance, int intensity, int errorCode, bool error = false); + /** + * @brief Construct a ScanRecord from all attributes. + * @param index The index of the record (starting from zero). + * @param angle The angle of the record (in radians). + * @param distance The distance that was measured in the angle (in millimeters). + * @param intensity The normalized spot intensity that was measured in the angle. + * @param errorCode The error code. + * @param error True if this record has an error. + */ + ScanRecord(int index, double angle, double distance, int intensity, int errorCode, bool error = false); - /** - * @brief Output the record as a string. - */ - friend std::ostream& operator<<(std::ostream& out, const ScanRecord& record); + /** + * @brief Output the record as a string. + */ + friend std::ostream& operator<<(std::ostream& out, const ScanRecord& record); }; } diff --git a/include/regilo/serialcontroller.hpp b/include/regilo/serialcontroller.hpp index 2b4dd88..a73d58f 100644 --- a/include/regilo/serialcontroller.hpp +++ b/include/regilo/serialcontroller.hpp @@ -34,18 +34,18 @@ namespace regilo { class SerialController : public StreamController { private: - std::string endpoint; + std::string endpoint; public: - using StreamController::StreamController; + using StreamController::StreamController; - /** - * @brief Connect the controller to a device. - * @param endpoint The endpoint with the path to the device (e.g. "/dev/ttyACM0"). - */ - virtual void connect(const std::string& endpoint) override; + /** + * @brief Connect the controller to a device. + * @param endpoint The endpoint with the path to the device (e.g. "/dev/ttyACM0"). + */ + virtual void connect(const std::string& endpoint) override; - virtual inline std::string getEndpoint() const override { return endpoint; } + virtual inline std::string getEndpoint() const override { return endpoint; } }; } diff --git a/include/regilo/socketcontroller.hpp b/include/regilo/socketcontroller.hpp index 0997e1e..3c39e91 100644 --- a/include/regilo/socketcontroller.hpp +++ b/include/regilo/socketcontroller.hpp @@ -36,33 +36,33 @@ namespace bai = ba::ip; class SocketController : public StreamController { public: - using StreamController::StreamController; + using StreamController::StreamController; - /** - * @brief Default destructor. - */ - virtual ~SocketController(); + /** + * @brief Default destructor. + */ + virtual ~SocketController(); - /** - * @brief Connect the controller to a device. - * @param endpoint The endpoint with the IP address and port of the device (e.g. "10.0.0.1:12345"). - */ - virtual void connect(const std::string& endpoint) override; + /** + * @brief Connect the controller to a device. + * @param endpoint The endpoint with the IP address and port of the device (e.g. "10.0.0.1:12345"). + */ + virtual void connect(const std::string& endpoint) override; - /** - * @brief Connect the controller to a device. - * @param ip The IP address of the device (e.g. "10.0.0.1"). - * @param port The port number of the device (e.g. 12345). - */ - void connect(const std::string& ip, unsigned short port); + /** + * @brief Connect the controller to a device. + * @param ipAddress The IP address of the device (e.g. "10.0.0.1"). + * @param port The port number of the device (e.g. 12345). + */ + void connect(const std::string& ipAddress, unsigned short port); - /** - * @brief Connect the controller to a device. - * @param endpoint The endpoint of the device. - */ - void connect(const bai::tcp::endpoint& endpoint); + /** + * @brief Connect the controller to a device. + * @param endpoint The endpoint of the device. + */ + void connect(const bai::tcp::endpoint& endpoint); - virtual std::string getEndpoint() const override; + virtual std::string getEndpoint() const override; }; } diff --git a/include/regilo/streamcontroller.hpp b/include/regilo/streamcontroller.hpp index 0cf25d5..a426c93 100644 --- a/include/regilo/streamcontroller.hpp +++ b/include/regilo/streamcontroller.hpp @@ -43,238 +43,238 @@ template class StreamController : public virtual IController { private: - ba::streambuf istreamBuffer; - std::istream istream; + ba::streambuf istreamBuffer; + std::istream istream; - ba::streambuf ostreamBuffer; - std::ostream ostream; + ba::streambuf ostreamBuffer; + std::ostream ostream; protected: - std::istringstream deviceOutput; ///< A buffer for the device output. - std::ostringstream deviceInput; ///< A buffer for the device input. + std::istringstream deviceOutput; ///< A buffer for the device output. + std::ostringstream deviceInput; ///< A buffer for the device input. - ba::io_service ioService; ///< The Boost IO service. - StreamT stream; ///< A stream (TCP, socket, etc.) that is used for read/write operations. + ba::io_service ioService; ///< The Boost IO service. + StreamT stream; ///< A stream (TCP, socket, etc.) that is used for read/write operations. - std::shared_ptr log; ///< A log that is connected to the controller. + std::shared_ptr log; ///< A log that is connected to the controller. - /** - * @brief Send a command from the device input to the device. - */ - template::value>::type* = nullptr> - void sendCommand(); + /** + * @brief Send a command from the device input to the device. + */ + template::value>::type* = nullptr> + void sendCommand(); - /** - * @brief Send a command from the device input to the device. - * @return A response to the command. - */ - template::value>::type* = nullptr> - Response sendCommand(); + /** + * @brief Send a command from the device input to the device. + * @return A response to the command. + */ + template::value>::type* = nullptr> + Response sendCommand(); public: - typedef StreamT Stream; ///< The stream type for this Controller. - - std::string REQUEST_END = "\n"; ///< A string that the request ends with. - std::string RESPONSE_END = "\n"; ///< A string that the response ends with. - - bool readResponse = true; ///< If true the sendCommand method reads a response. - bool readCommand = true; ///< If true the input command is read from the response at first. - - /** - * @brief Default constructor. - */ - StreamController(); - - /** - * @brief Controller with a log file specified by a path. - * @param logPath Path to the log file. - */ - StreamController(const std::string& logPath); - - /** - * @brief Controller with a log specified by a stream. - * @param logStream The log stream. - */ - StreamController(std::iostream& logStream); - - /** - * @brief Default destructor. - */ - virtual ~StreamController(); - - virtual inline bool isConnected() const override { return stream.is_open(); } - - virtual inline std::shared_ptr getLog() override { return log; } - virtual inline std::shared_ptr getLog() const override { return log; } - - virtual void setLog(std::shared_ptr log) override; - - virtual std::string sendCommand(const std::string& command) final override; - - /** - * @brief Send a command to the device. - * @param command A command with all parameters. - * @return A response to the command. - */ - template - Response sendCommand(const Command& command); - - /** - * @brief Send a command to the device. - * @param command A command without parameters. - * @param params Parameters that will be inserted into the command (separated by space). - * @return A response to the command. - */ - template - Response sendCommand(const Command& command, const Args& ... params); - - /** - * @brief Create a command with the specified parameters (printf formatting is used) and send it to the device. - * @param commandFormat A command format without parameters. - * @param params Parameters that will be inserted into the command. - * @return A response to the command. - */ - template - Response sendFormattedCommand(const std::string& commandFormat, Args... params); - - /** - * @brief Create a command with the specified parameters (printf formatting is used). - * @param commandFormat A command format without parameters. - * @param params Parameters that will be inserted into the command. - * @return The command with the parameters. - */ - template - std::string createFormattedCommand(const std::string& commandFormat, Args... params) const; + typedef StreamT Stream; ///< The stream type for this Controller. + + std::string REQUEST_END = "\n"; ///< A string that the request ends with. + std::string RESPONSE_END = "\n"; ///< A string that the response ends with. + + bool readResponse = true; ///< If true the sendCommand method reads a response. + bool readCommand = true; ///< If true the input command is read from the response at first. + + /** + * @brief Default constructor. + */ + StreamController(); + + /** + * @brief Controller with a log file specified by a path. + * @param logPath Path to the log file. + */ + StreamController(const std::string& logPath); + + /** + * @brief Controller with a log specified by a stream. + * @param logStream The log stream. + */ + StreamController(std::iostream& logStream); + + /** + * @brief Default destructor. + */ + virtual ~StreamController(); + + virtual inline bool isConnected() const override { return stream.is_open(); } + + virtual inline std::shared_ptr getLog() override { return log; } + virtual inline std::shared_ptr getLog() const override { return log; } + + virtual void setLog(std::shared_ptr log) override; + + virtual std::string sendCommand(const std::string& command) final override; + + /** + * @brief Send a command to the device. + * @param command A command with all parameters. + * @return A response to the command. + */ + template + Response sendCommand(const Command& command); + + /** + * @brief Send a command to the device. + * @param command A command without parameters. + * @param params Parameters that will be inserted into the command (separated by space). + * @return A response to the command. + */ + template + Response sendCommand(const Command& command, const Args& ... params); + + /** + * @brief Create a command with the specified parameters (printf formatting is used) and send it to the device. + * @param commandFormat A command format without parameters. + * @param params Parameters that will be inserted into the command. + * @return A response to the command. + */ + template + Response sendFormattedCommand(const std::string& commandFormat, Args... params); + + /** + * @brief Create a command with the specified parameters (printf formatting is used). + * @param commandFormat A command format without parameters. + * @param params Parameters that will be inserted into the command. + * @return The command with the parameters. + */ + template + std::string createFormattedCommand(const std::string& commandFormat, Args... params) const; }; template StreamController::StreamController() : - istream(&istreamBuffer), - ostream(&ostreamBuffer), - stream(ioService) + istream(&istreamBuffer), + ostream(&ostreamBuffer), + stream(ioService) { } template StreamController::StreamController(const std::string& logPath) : StreamController() { - if(!logPath.empty()) - { - log.reset(new Log(logPath)); - } + if(!logPath.empty()) + { + log.reset(new Log(logPath)); + } } template StreamController::StreamController(std::iostream& logStream) : StreamController() { - this->log.reset(new Log(logStream)); + this->log.reset(new Log(logStream)); } template StreamController::~StreamController() { - if(stream.is_open()) stream.close(); + if(stream.is_open()) stream.close(); } template void StreamController::setLog(std::shared_ptr log) { - std::shared_ptr logPointer = std::dynamic_pointer_cast(log); - this->log.swap(logPointer); + std::shared_ptr logPointer = std::dynamic_pointer_cast(log); + this->log.swap(logPointer); } template std::string StreamController::sendCommand(const std::string& command) { - sendCommand<>(command); + sendCommand<>(command); - std::string response; - std::getline(deviceOutput, response, '\0'); + std::string response; + std::getline(deviceOutput, response, '\0'); - return response; + return response; } template template Response StreamController::sendCommand(const Command& command) { - deviceInput << command; - return sendCommand(); + deviceInput << command; + return sendCommand(); } template template Response StreamController::sendCommand(const Command& command, const Args& ... params) { - deviceInput << command << ' '; - return sendCommand(params...); + deviceInput << command << ' '; + return sendCommand(params...); } template template Response StreamController::sendFormattedCommand(const std::string& commandFormat, Args... params) { - return sendCommand(createFormattedCommand(commandFormat, params...)); + return sendCommand(createFormattedCommand(commandFormat, params...)); } template template::value>::type*> void StreamController::sendCommand() { - deviceInput << REQUEST_END; + deviceInput << REQUEST_END; - std::string input = deviceInput.str(); - ostream << input; + std::string input = deviceInput.str(); + ostream << input; - ba::write(stream, ostreamBuffer); - ostream.flush(); + ba::write(stream, ostreamBuffer); + ostream.flush(); - deviceInput.clear(); - deviceInput.str(""); + deviceInput.clear(); + deviceInput.str(""); - std::string output; - if(readResponse) - { - ba::read_until(stream, istreamBuffer, RESPONSE_END); + std::string output; + if(readResponse) + { + ba::read_until(stream, istreamBuffer, RESPONSE_END); - if(readCommand) - { - std::string cmdInput; - getLine(istream, cmdInput, REQUEST_END); - } + if(readCommand) + { + std::string cmdInput; + getLine(istream, cmdInput, REQUEST_END); + } - getLine(istream, output, RESPONSE_END); - deviceOutput.clear(); - deviceOutput.str(output); - } + getLine(istream, output, RESPONSE_END); + deviceOutput.clear(); + deviceOutput.str(output); + } - if(log != nullptr) log->write(input, output); + if(log != nullptr) log->write(input, output); } template template::value>::type*> Response StreamController::sendCommand() { - sendCommand(); + sendCommand(); - Response output; - deviceOutput >> output; + Response output; + deviceOutput >> output; - return output; + return output; } template template std::string StreamController::createFormattedCommand(const std::string& command, Args... params) const { - std::size_t size = std::snprintf(nullptr, 0, command.c_str(), params...) + 1; - char *buffer = new char[size]; - std::snprintf(buffer, size, command.c_str(), params...); + std::size_t size = std::snprintf(nullptr, 0, command.c_str(), params...) + 1; + char *buffer = new char[size]; + std::snprintf(buffer, size, command.c_str(), params...); - std::string result(buffer, buffer + size - 1); - delete[] buffer; + std::string result(buffer, buffer + size - 1); + delete[] buffer; - return result; + return result; } } diff --git a/include/regilo/timedlog.hpp b/include/regilo/timedlog.hpp index 043dbb4..8e2d1d6 100644 --- a/include/regilo/timedlog.hpp +++ b/include/regilo/timedlog.hpp @@ -41,17 +41,17 @@ class TimedLog; class ITimedLogMetadata { public: - /** - * @brief Get the num of ratio. - * @return The num value. - */ - virtual std::intmax_t getNum() const = 0; - - /** - * @brief Get the den of ratio. - * @return The den value. - */ - virtual std::intmax_t getDen() const = 0; + /** + * @brief Get the num of ratio. + * @return The num value. + */ + virtual std::intmax_t getNum() const = 0; + + /** + * @brief Get the den of ratio. + * @return The den value. + */ + virtual std::intmax_t getDen() const = 0; }; /** @@ -61,25 +61,25 @@ template class TimedLogMetadata : public LogMetadata, public ITimedLogMetadata { private: - std::intmax_t num = DurationT::period::num; - std::intmax_t den = DurationT::period::den; + std::intmax_t num = DurationT::period::num; + std::intmax_t den = DurationT::period::den; protected: - /** - * @brief The default constructor is available only in derived and friend classes. - */ - TimedLogMetadata(); + /** + * @brief The default constructor is available only in derived and friend classes. + */ + TimedLogMetadata(); public: - /** - * @brief The default destructor. - */ - virtual ~TimedLogMetadata() = default; + /** + * @brief The default destructor. + */ + virtual ~TimedLogMetadata() = default; - inline virtual std::intmax_t getNum() const override final { return num; } - inline virtual std::intmax_t getDen() const override final { return den; } + inline virtual std::intmax_t getNum() const override final { return num; } + inline virtual std::intmax_t getDen() const override final { return den; } - friend class TimedLog; + friend class TimedLog; }; /** @@ -88,35 +88,38 @@ class TimedLogMetadata : public LogMetadata, public ITimedLogMetadata class ITimedLog : public virtual ILog { public: - /** - * @brief Default destructor. - */ - virtual ~ITimedLog() = default; - - /** - * @brief Get the associated timed metadata. - * @return A pointer to timed metadata - */ - virtual const ITimedLogMetadata* getTimedMetadata() const = 0; - - /** - * @brief Get the last command time (after reading). - * @return Time since epoch as std::chrono::nanoseconds. - */ - virtual std::chrono::nanoseconds getLastCommandNanoseconds() const = 0; - - /** - * @brief Get the last command time (after reading). - * @return Time since epoch as Duration. - */ - template - inline Duration getLastCommandTimeAs() const { return std::chrono::duration_cast(this->getLastCommandNanoseconds()); } - - /** - * @brief Sync command times with real time. It means that all read methods will block - * their executions until the current time is bigger than the command time. - */ - virtual void syncTime(bool sync = true) = 0; + /** + * @brief Default destructor. + */ + virtual ~ITimedLog() = default; + + /** + * @brief Get the associated timed metadata. + * @return A pointer to timed metadata + */ + virtual const ITimedLogMetadata* getTimedMetadata() const = 0; + + /** + * @brief Get the last command time (after reading). + * @return Time since epoch as std::chrono::nanoseconds. + */ + virtual std::chrono::nanoseconds getLastCommandNanoseconds() const = 0; + + /** + * @brief Get the last command time (after reading). + * @return Time since epoch as Duration. + */ + template + inline Duration getLastCommandTimeAs() const + { + return std::chrono::duration_cast(this->getLastCommandNanoseconds()); + } + + /** + * @brief Sync command times with real time. It means that all read methods will block + * their executions until the current time is bigger than the command time. + */ + virtual void syncTime(bool sync = true) = 0; }; /** @@ -126,44 +129,51 @@ template class TimedLog : public Log, public ITimedLog { private: - std::mutex streamMutex; + std::mutex streamMutex; - DurationT lastCommandTime; + DurationT lastCommandTime; - DurationT firstReadTime = DurationT::zero(); - DurationT firstWriteTime = DurationT::min(); + DurationT firstReadTime = DurationT::zero(); + DurationT firstWriteTime = DurationT::min(); protected: - virtual void readMetadata(std::istream& metaStream) override; - virtual void writeMetadata(std::ostream& metaStream) override; + virtual void readMetadata(std::istream& metaStream) override; + virtual void writeMetadata(std::ostream& metaStream) override; - virtual std::string readData(std::string& logCommand) override; - virtual void writeData(const std::string& command, const std::string& response) override; + virtual std::string readData(std::string& logCommand) override; + virtual void writeData(const std::string& command, const std::string& response) override; public: - typedef DurationT Duration; ///< The duration type for this log. - - using Log::Log; - - /** - * @brief The default destructor. - */ - virtual ~TimedLog() = default; - - virtual inline const ITimedLogMetadata* getTimedMetadata() const override { return (TimedLogMetadata*)metadata; } - - inline virtual std::chrono::nanoseconds getLastCommandNanoseconds() const override - { - return std::chrono::duration_cast(lastCommandTime); - } - - /** - * @brief Get the last command time (after reading). - * @return Time since epoch as Duration. - */ - inline DurationT getLastCommandTime() const { return lastCommandTime; } - - virtual inline void syncTime(bool sync = true) override { firstReadTime = (sync ? DurationT::max() : DurationT::zero()); } + typedef DurationT Duration; ///< The duration type for this log. + + using Log::Log; + using Log::readMetadata; + + /** + * @brief The default destructor. + */ + virtual ~TimedLog() = default; + + virtual inline const ITimedLogMetadata* getTimedMetadata() const override + { + return (TimedLogMetadata*)metadata; + } + + inline virtual std::chrono::nanoseconds getLastCommandNanoseconds() const override + { + return std::chrono::duration_cast(lastCommandTime); + } + + /** + * @brief Get the last command time (after reading). + * @return Time since epoch as Duration. + */ + inline DurationT getLastCommandTime() const { return lastCommandTime; } + + virtual inline void syncTime(bool sync = true) override + { + firstReadTime = (sync ? DurationT::max() : DurationT::zero()); + } }; extern template class TimedLog; @@ -173,72 +183,73 @@ extern template class TimedLog; template TimedLogMetadata::TimedLogMetadata() : - LogMetadata("timedlog", 2) + LogMetadata("timedlog", 2) { } template void TimedLog::readMetadata(std::istream& metaStream) { - if(metadata == nullptr) metadata = new TimedLogMetadata(); - Log::readMetadata(metaStream); + if(metadata == nullptr) metadata = new TimedLogMetadata(); + Log::readMetadata(metaStream); - readName(metaStream, "timeres"); - TimedLogMetadata *timedMetadata = (TimedLogMetadata*)metadata; - metaStream >> timedMetadata->num >> timedMetadata->den; + readName(metaStream, "timeres"); + TimedLogMetadata *timedMetadata = (TimedLogMetadata*)metadata; + metaStream >> timedMetadata->num >> timedMetadata->den; } template void TimedLog::writeMetadata(std::ostream& metaStream) { - if(metadata == nullptr) metadata = new TimedLogMetadata(); - Log::writeMetadata(metaStream); + if(metadata == nullptr) metadata = new TimedLogMetadata(); + Log::writeMetadata(metaStream); - metaStream << "timeres " << DurationT::period::num << ' ' << DurationT::period::den << std::endl; + metaStream << "timeres " << DurationT::period::num << ' ' << DurationT::period::den + << std::endl; } template std::string TimedLog::readData(std::string& logCommand) { - std::lock_guard streamLock(streamMutex); - - std::string response = Log::readData(logCommand); - - std::int64_t commandTimeCount = 0; - readName(stream, 't'); - stream >> commandTimeCount; - - if(stream) - { - long double numRatio = getTimedMetadata()->getNum() / (long double) DurationT::period::num; - long double denRation = DurationT::period::den / (long double) getTimedMetadata()->getDen(); - lastCommandTime = DurationT(std::int64_t(std::round(commandTimeCount * numRatio * denRation))); - - if(firstReadTime == DurationT::max()) firstReadTime = epoch(); - else - { - DurationT elapsed = epoch() - firstReadTime; - - while(elapsed < lastCommandTime) - { - std::this_thread::sleep_for(lastCommandTime - elapsed); - elapsed = epoch() - firstReadTime; - } - } - } - - return response; + std::lock_guard streamLock(streamMutex); + + std::string response = Log::readData(logCommand); + + std::int64_t timeCount = 0; + readName(stream, 't'); + stream >> timeCount; + + if(stream) + { + long double numRatio = getTimedMetadata()->getNum() / (long double) DurationT::period::num; + long double denRation = DurationT::period::den / (long double) getTimedMetadata()->getDen(); + lastCommandTime = DurationT(std::int64_t(std::round(timeCount * numRatio * denRation))); + + if(firstReadTime == DurationT::max()) firstReadTime = epoch(); + else + { + DurationT elapsed = epoch() - firstReadTime; + + while(elapsed < lastCommandTime) + { + std::this_thread::sleep_for(lastCommandTime - elapsed); + elapsed = epoch() - firstReadTime; + } + } + } + + return response; } template void TimedLog::writeData(const std::string& command, const std::string& response) { - std::lock_guard streamLock(streamMutex); + std::lock_guard streamLock(streamMutex); - Log::writeData(command, response); + Log::writeData(command, response); - if(firstWriteTime == DurationT::min()) firstWriteTime = epoch(); - stream << "t " << (epoch() - firstWriteTime).count() << std::endl; + if(firstWriteTime == DurationT::min()) firstWriteTime = epoch(); + stream << "t " << (epoch() - firstWriteTime).count() << std::endl; } } diff --git a/include/regilo/utils.hpp b/include/regilo/utils.hpp index c3e1d30..8d77b27 100644 --- a/include/regilo/utils.hpp +++ b/include/regilo/utils.hpp @@ -34,8 +34,8 @@ namespace regilo { template T epoch() { - auto sinceEpoch = std::chrono::system_clock::now().time_since_epoch(); - return std::chrono::duration_cast(sinceEpoch); + auto sinceEpoch = std::chrono::system_clock::now().time_since_epoch(); + return std::chrono::duration_cast(sinceEpoch); } /** diff --git a/include/regilo/version.hpp b/include/regilo/version.hpp index 35758a2..6f4a2d8 100644 --- a/include/regilo/version.hpp +++ b/include/regilo/version.hpp @@ -32,11 +32,17 @@ namespace regilo { class Version { public: - static const std::string VERSION; ///< The whole version number in format [.[.[.]]]. - static const std::string VERSION_MAJOR; ///< The major part of the version number (format [.[.[.]]]). - static const std::string VERSION_MINOR; ///< The minor part of the version number (format [.[.[.]]]). - static const std::string VERSION_PATCH; ///< The patch part of the version number (format [.[.[.]]]). - static const std::string VERSION_TWEAK; ///< The tweak part of the version number (format [.[.[.]]]). + ///< The whole version number in format [.[.]]. + static const std::string VERSION; + + ///< The major part of the version number (format [.[.]]). + static const std::string VERSION_MAJOR; + + ///< The minor part of the version number (format [.[.]]). + static const std::string VERSION_MINOR; + + ///< The patch part of the version number (format [.[.]]). + static const std::string VERSION_PATCH; }; } diff --git a/src/regilo/log.cpp b/src/regilo/log.cpp index 1a62f49..c0dbeb1 100644 --- a/src/regilo/log.cpp +++ b/src/regilo/log.cpp @@ -32,218 +32,224 @@ InvalidLogException::InvalidLogException(const std::string& message) : std::runt } LogMetadata::LogMetadata(const std::string& type, int version) : - type(type), version(version) + type(type), version(version) { } Log::Log(const std::string& filePath) : - filePath(filePath), - fileStream(new std::fstream(filePath, std::fstream::in | std::fstream::out | std::fstream::app)), - stream(*fileStream) + filePath(filePath), + fileStream(new std::fstream(filePath, std::fstream::in | std::fstream::out | std::fstream::app)), + stream(*fileStream) { } Log::Log(std::iostream& stream) : - fileStream(nullptr), - stream(stream) + fileStream(nullptr), + stream(stream) { } Log::~Log() { - delete fileStream; - delete metadata; + delete fileStream; + delete metadata; } void Log::readName(std::istream& stream, char name) { - char logName; - stream >> logName; + char logName; + stream >> logName; - if(stream) - { - if(logName == '#') - { - std::string comment; - std::getline(stream, comment); + if(stream) + { + if(logName == '#') + { + std::string comment; + std::getline(stream, comment); - readName(stream, name); - } - else if(name != logName) throw InvalidLogException('\'' + std::string(1, logName) + "' found but '" + name + "' expected."); - } + readName(stream, name); + } + else if(name != logName) + { + throw InvalidLogException('\'' + std::string(1, logName) + "' found but '" + name + "' expected."); + } + } } void Log::readName(std::istream& stream, const std::string& name) { - std::string logName; - stream >> logName; + std::string logName; + stream >> logName; - if(stream) - { - if(logName.front() == '#') - { - std::string comment; - std::getline(stream, comment); + if(stream) + { + if(logName.front() == '#') + { + std::string comment; + std::getline(stream, comment); - readName(stream, name); - } - else if(name != logName) throw InvalidLogException('\'' + logName + "' found but '" + name + "' expected."); - } + readName(stream, name); + } + else if(name != logName) + { + throw InvalidLogException('\'' + logName + "' found but '" + name + "' expected."); + } + } } std::string Log::readValue(std::istream& stream) { - std::size_t length; - stream >> length; + std::size_t length; + stream >> length; - // Read the space between length and data. - stream.get(); + // Read the space between length and data. + stream.get(); - std::string value; - if(stream) - { - char *data = new char[length]; - stream.read(data, length); + std::string value; + if(stream) + { + char *data = new char[length]; + stream.read(data, length); - value = std::string(data, length); - delete[] data; - } + value = std::string(data, length); + delete[] data; + } - return value; + return value; } std::string Log::readNameValue(std::istream& stream, char name) { - readName(stream, name); - return readValue(stream); + readName(stream, name); + return readValue(stream); } std::string Log::readNameValue(std::istream& stream, const std::string& name) { - readName(stream, name); - return readValue(stream); + readName(stream, name); + return readValue(stream); } void Log::readMetadata() { - if(!metadataRead) - { - std::string metaLine; - std::stringstream metaStream; - while(std::getline(stream, metaLine) && !metaLine.empty()) - { - if(metaLine.front() == '#') continue; + if(!metadataRead) + { + std::string metaLine; + std::stringstream metaStream; + while(std::getline(stream, metaLine) && !metaLine.empty()) + { + if(metaLine.front() == '#') continue; - metaStream << metaLine << std::endl; - } + metaStream << metaLine << std::endl; + } - readMetadata(metaStream); - metadataRead = true; - } + readMetadata(metaStream); + metadataRead = true; + } } void Log::readMetadata(std::istream& metaStream) { - if(metadata == nullptr) metadata = new LogMetadata(); + if(metadata == nullptr) metadata = new LogMetadata(); - readName(metaStream, "type"); - metaStream >> metadata->type; + readName(metaStream, "type"); + metaStream >> metadata->type; - readName(metaStream, "version"); - metaStream >> metadata->version; + readName(metaStream, "version"); + metaStream >> metadata->version; } void Log::writeMetadata(std::ostream& metaStream) { - if(metadata == nullptr) metadata = new LogMetadata(); + if(metadata == nullptr) metadata = new LogMetadata(); - metaStream << "type " << metadata->type << std::endl; - metaStream << "version " << metadata->version << std::endl; + metaStream << "type " << metadata->type << std::endl; + metaStream << "version " << metadata->version << std::endl; } std::string Log::readData(std::string& logCommand) { - logCommand = readNameValue(stream, 'c'); - stream.get(); // Read the new line after the command + logCommand = readNameValue(stream, 'c'); + stream.get(); // Read the new line after the command - std::string response = readNameValue(stream, 'r'); - stream.get(); // Read the new line after the response + std::string response = readNameValue(stream, 'r'); + stream.get(); // Read the new line after the response - return response; + return response; } std::string Log::read() { - std::string logCommand; - return read(logCommand); + std::string logCommand; + return read(logCommand); } std::string Log::read(std::string& logCommand) { - std::lock_guard streamLock(streamMutex); + std::lock_guard streamLock(streamMutex); - readMetadata(); + readMetadata(); - std::string response = readData(logCommand); + std::string response = readData(logCommand); - std::string responseEnd; - while(std::getline(stream, responseEnd) && !responseEnd.empty()) - { - if(responseEnd.front() != '#') break; - } + std::string responseEnd; + while(std::getline(stream, responseEnd) && !responseEnd.empty()) + { + if(responseEnd.front() != '#') break; + } - if(!responseEnd.empty()) throw InvalidLogException("Missing a new line after data."); + if(!responseEnd.empty()) throw InvalidLogException("Missing a new line after data."); - return response; + return response; } std::string Log::readCommand(const std::string& command) { - std::string logCommand; - return readCommand(command, logCommand); + std::string logCommand; + return readCommand(command, logCommand); } std::string Log::readCommand(const std::string& command, std::string& logCommand) { - std::string response; - do - { - response = read(logCommand); - } - while(!(boost::algorithm::starts_with(logCommand, command) || isEnd())); + std::string response; + do + { + response = read(logCommand); + } + while(!(boost::algorithm::starts_with(logCommand, command) || isEnd())); - return response; + return response; } void Log::writeData(const std::string& command, const std::string& response) { - stream << "c " << command.length() << ' ' << command << std::endl; + stream << "c " << command.length() << ' ' << command << std::endl; - stream << "r " << response.length(); - if(!response.empty()) stream << ' ' << response; - stream << std::endl; + stream << "r " << response.length(); + if(!response.empty()) stream << ' ' << response; + stream << std::endl; } void Log::write(const std::string& command, const std::string& response) { - std::lock_guard streamLock(streamMutex); + std::lock_guard streamLock(streamMutex); - if(!metadataWritten) - { - std::ostringstream metaStream; - writeMetadata(metaStream); + if(!metadataWritten) + { + std::ostringstream metaStream; + writeMetadata(metaStream); - stream << metaStream.str() << std::endl; - metadataWritten = true; - } + stream << metaStream.str() << std::endl; + metadataWritten = true; + } - writeData(command, response); - stream << std::endl; + writeData(command, response); + stream << std::endl; } void Log::close() { - if(fileStream != nullptr) fileStream->close(); + if(fileStream != nullptr) fileStream->close(); } } diff --git a/src/regilo/scandata.cpp b/src/regilo/scandata.cpp index 078d598..9b27fb0 100644 --- a/src/regilo/scandata.cpp +++ b/src/regilo/scandata.cpp @@ -25,28 +25,29 @@ namespace regilo { -ScanData::ScanData(std::size_t scanId, double rotationSpeed) : - scanId(scanId), rotationSpeed(rotationSpeed) +ScanData::ScanData(std::size_t index, double rotationSpeed) : + index(index), + rotationSpeed(rotationSpeed) { } std::ostream& operator<<(std::ostream& out, const ScanData& data) { - out << "ScanData(" - << data.scanId - << ", " - << data.rotationSpeed - << ", " - << data.size() - << ')' - << std::endl; - - for(const ScanRecord& record : data) - { - out << record << std::endl; - } - - return out; + out << "ScanData(" + << data.index + << ", " + << data.rotationSpeed + << ", " + << data.size() + << ')' + << std::endl; + + for(const ScanRecord& record : data) + { + out << record << std::endl; + } + + return out; } } diff --git a/src/regilo/scanrecord.cpp b/src/regilo/scanrecord.cpp index e9ecafe..509a5ef 100644 --- a/src/regilo/scanrecord.cpp +++ b/src/regilo/scanrecord.cpp @@ -26,31 +26,38 @@ namespace regilo { -ScanRecord::ScanRecord(int id, double angle, double distance, int intensity, int errorCode, bool error) : - id(id), - angle(angle), - distance(distance), - intensity(intensity), - errorCode(errorCode), - error(error) +ScanRecord::ScanRecord( + int index, + double angle, + double distance, + int intensity, + int errorCode, + bool error +) : + index(index), + angle(angle), + distance(distance), + intensity(intensity), + errorCode(errorCode), + error(error) { } std::ostream& operator<<(std::ostream& out, const ScanRecord& record) { - out << "ScanRecord(" - << record.id - << ": " - << record.angle * 180 * M_1_PI - << "°; " - << record.distance - << "mm"; + out << "ScanRecord(" + << record.index + << ": " + << record.angle * 180 * M_1_PI + << "°; " + << record.distance + << "mm"; - if(record.error) out << "; error"; + if(record.error) out << "; error"; - out << ')'; + out << ')'; - return out; + return out; } } diff --git a/src/regilo/serialcontroller.cpp b/src/regilo/serialcontroller.cpp index a0b3f66..c7ad11a 100644 --- a/src/regilo/serialcontroller.cpp +++ b/src/regilo/serialcontroller.cpp @@ -25,8 +25,8 @@ namespace regilo { void SerialController::connect(const std::string& endpoint) { - this->endpoint = endpoint; - stream.open(endpoint); + this->endpoint = endpoint; + stream.open(endpoint); } } diff --git a/src/regilo/socketcontroller.cpp b/src/regilo/socketcontroller.cpp index 2d858fb..474026e 100644 --- a/src/regilo/socketcontroller.cpp +++ b/src/regilo/socketcontroller.cpp @@ -25,48 +25,48 @@ namespace regilo { SocketController::~SocketController() { - if(stream.is_open()) - { - boost::system::error_code ec; - stream.shutdown(bai::tcp::socket::shutdown_both, ec); - } + if(stream.is_open()) + { + boost::system::error_code errorCode; + stream.shutdown(bai::tcp::socket::shutdown_both, errorCode); + } } void SocketController::connect(const std::string& endpoint) { - std::string ip = endpoint; - unsigned short port = 0; + std::string ipAddress = endpoint; + unsigned short port = 0; - std::size_t colonPos = endpoint.find(':'); - if(colonPos != std::string::npos) - { - ip = endpoint.substr(0, colonPos); - port = static_cast(std::stoul(endpoint.substr(colonPos + 1))); - } + std::size_t colonPos = endpoint.find(':'); + if(colonPos != std::string::npos) + { + ipAddress = endpoint.substr(0, colonPos); + port = static_cast(std::stoul(endpoint.substr(colonPos + 1))); + } - connect(ip, port); + connect(ipAddress, port); } -void SocketController::connect(const std::string& ip, unsigned short port) +void SocketController::connect(const std::string& ipAddress, unsigned short port) { - connect(bai::tcp::endpoint(bai::address::from_string(ip), port)); + connect(bai::tcp::endpoint(bai::address::from_string(ipAddress), port)); } void SocketController::connect(const bai::tcp::endpoint& endpoint) { - stream.connect(endpoint); + stream.connect(endpoint); } std::string SocketController::getEndpoint() const { - if(!isConnected()) return ""; + if(!isConnected()) return ""; - Stream::endpoint_type endpoint = stream.remote_endpoint(); + Stream::endpoint_type endpoint = stream.remote_endpoint(); - std::string ip = endpoint.address().to_string(); - std::string port = std::to_string(endpoint.port()); + std::string ipAddress = endpoint.address().to_string(); + std::string port = std::to_string(endpoint.port()); - return ip + ':' + port; + return ipAddress + ':' + port; } } diff --git a/src/regilo/utils.cpp b/src/regilo/utils.cpp index f5c317b..5499386 100644 --- a/src/regilo/utils.cpp +++ b/src/regilo/utils.cpp @@ -25,45 +25,43 @@ namespace regilo { std::istream& getLine(std::istream& stream, std::string& line, const std::string& delim) { - if(delim.empty()) return std::getline(stream, line); - else if(delim.size() == 1) return std::getline(stream, line, delim.front()); - else - { - char c; - stream.get(c); + if(delim.empty()) return std::getline(stream, line); + if(delim.size() == 1) return std::getline(stream, line, delim.front()); - std::string delimPart, result; - while(stream) - { - if(c == delim.at(delimPart.size())) - { - delimPart += c; - if(delimPart.size() == delim.size()) - { - delimPart.clear(); - break; - } - } - else - { - if(!delimPart.empty()) - { - result += delimPart; - delimPart.clear(); - } + char character; + stream.get(character); - result += c; - } + std::string delimPart, result; + while(stream) + { + if(character == delim.at(delimPart.size())) + { + delimPart += character; + if(delimPart.size() == delim.size()) + { + delimPart.clear(); + break; + } + } + else + { + if(!delimPart.empty()) + { + result += delimPart; + delimPart.clear(); + } - if(stream.peek() == EOF) break; - else stream.get(c); - } + result += character; + } - if(!delimPart.empty()) result += delimPart; - if(!result.empty()) line = result; + if(stream.peek() == EOF) break; + else stream.get(character); + } - return stream; - } + if(!delimPart.empty()) result += delimPart; + if(!result.empty()) line = result; + + return stream; } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cfdf14d..9f6c54a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,4 +21,4 @@ target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) target_link_libraries(${PROJECT_NAME} regilo) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND - ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/data $/data) + ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/data $/data) diff --git a/tests/include/simulators/serialsimulator.hpp b/tests/include/simulators/serialsimulator.hpp index 292e5ae..4db2729 100644 --- a/tests/include/simulators/serialsimulator.hpp +++ b/tests/include/simulators/serialsimulator.hpp @@ -31,23 +31,23 @@ class SerialSimulator : public Simulator { private: - int ptmx; - bool opened = false; + int ptmx; + bool opened = false; protected: - inline virtual std::string read() override { return read(256); } - std::string read(std::size_t bufferSize); - virtual bool write(const std::string& data) override; + inline virtual std::string read() override { return read(256); } + std::string read(std::size_t bufferSize); + virtual bool write(const std::string& data) override; public: - using Simulator::Simulator; - virtual ~SerialSimulator(); + using Simulator::Simulator; + virtual ~SerialSimulator(); - virtual void start() override; - virtual void stop() override; + virtual void start() override; + virtual void stop() override; - inline virtual bool isRunning() const override { return opened; } - inline virtual std::string getEndpoint() const override { return std::string(ptsname(ptmx)); } + inline virtual bool isRunning() const override { return opened; } + inline virtual std::string getEndpoint() const override { return std::string(ptsname(ptmx)); } }; #endif // SERIALSIMULATOR_HPP diff --git a/tests/include/simulators/simulator.hpp b/tests/include/simulators/simulator.hpp index 924b152..70258fb 100644 --- a/tests/include/simulators/simulator.hpp +++ b/tests/include/simulators/simulator.hpp @@ -29,27 +29,27 @@ class Simulator { protected: - regilo::Log log; + regilo::Log log; - virtual std::string read() = 0; - virtual bool write(const std::string& data) = 0; + virtual std::string read() = 0; + virtual bool write(const std::string& data) = 0; public: - std::string requestEnd = "\n"; - std::string responseEnd = "\n"; + std::string requestEnd = "\n"; + std::string responseEnd = "\n"; - Simulator(const std::string& filePath); - Simulator(std::iostream& stream); + Simulator(const std::string& filePath); + Simulator(std::iostream& stream); - virtual ~Simulator() = default; + virtual ~Simulator() = default; - virtual void start() = 0; - virtual void stop() = 0; + virtual void start() = 0; + virtual void stop() = 0; - virtual bool isRunning() const = 0; - virtual std::string getEndpoint() const = 0; + virtual bool isRunning() const = 0; + virtual std::string getEndpoint() const = 0; - virtual bool run(); + virtual bool run(); }; #endif // SIMULATOR_HPP diff --git a/tests/include/simulators/socketsimulator.hpp b/tests/include/simulators/socketsimulator.hpp index 77e1c73..7998c30 100644 --- a/tests/include/simulators/socketsimulator.hpp +++ b/tests/include/simulators/socketsimulator.hpp @@ -35,30 +35,30 @@ namespace bai = boost::asio::ip; class SocketSimulator : public Simulator { private: - boost::asio::io_service ioService; - bai::tcp::acceptor acceptor; - bai::tcp::socket socket; + boost::asio::io_service ioService; + bai::tcp::acceptor acceptor; + bai::tcp::socket socket; - boost::asio::streambuf socketIStreamBuffer, socketOStreamBuffer; - std::istream socketIStream; - std::ostream socketOStream; + boost::asio::streambuf socketIStreamBuffer, socketOStreamBuffer; + std::istream socketIStream; + std::ostream socketOStream; - virtual std::string read() override; - virtual bool write(const std::string& data) override; + virtual std::string read() override; + virtual bool write(const std::string& data) override; public: - SocketSimulator(const std::string& filePath, unsigned short port); - SocketSimulator(std::iostream& stream, unsigned short port); + SocketSimulator(const std::string& filePath, unsigned short port); + SocketSimulator(std::iostream& stream, unsigned short port); - virtual ~SocketSimulator(); + virtual ~SocketSimulator(); - virtual void start() override; - virtual void stop() override; + virtual void start() override; + virtual void stop() override; - virtual bool isRunning() const override; - virtual std::string getEndpoint() const override; + virtual bool isRunning() const override; + virtual std::string getEndpoint() const override; - virtual bool run() override; + virtual bool run() override; }; #endif // SOCKETSIMULATOR_HPP diff --git a/tests/src/simulators/serialsimulator.cpp b/tests/src/simulators/serialsimulator.cpp index 086775c..a77d826 100644 --- a/tests/src/simulators/serialsimulator.cpp +++ b/tests/src/simulators/serialsimulator.cpp @@ -25,63 +25,57 @@ SerialSimulator::~SerialSimulator() { - stop(); + stop(); } void SerialSimulator::start() { - if(!opened) - { - ptmx = ::open("/dev/ptmx", O_RDWR | O_NOCTTY); - opened = (ptmx != -1 && grantpt(ptmx) == 0 && unlockpt(ptmx) == 0); - } + if(!opened) + { + ptmx = ::open("/dev/ptmx", O_RDWR | O_NOCTTY); + opened = (ptmx != -1 && grantpt(ptmx) == 0 && unlockpt(ptmx) == 0); + } } void SerialSimulator::stop() { - if(opened) - { - ::close(ptmx); - opened = false; - } + if(opened) + { + ::close(ptmx); + opened = false; + } } std::string SerialSimulator::read(std::size_t bufferSize) { - std::string response; - char *buffer = new char[bufferSize]; + std::string response; + char *buffer = new char[bufferSize]; - ssize_t readBytes; - std::size_t found = 0; - while((readBytes = ::read(ptmx, buffer, bufferSize - 1)) > 0) - { - if(!requestEnd.empty()) - { - for(int i = 0; i < readBytes; i++) - { - if(buffer[i] == requestEnd[found]) - { - found++; - if(found == requestEnd.length()) - { - response.append(buffer, i + 1); - delete[] buffer; + ssize_t readBytes; + while((readBytes = ::read(ptmx, buffer, bufferSize - 1)) > 0) + { + if(!requestEnd.empty()) + { + std::string bufferString(buffer, readBytes); + std::size_t requestEndPos = bufferString.find(requestEnd); - return response; - } - } - else found = 0; - } - } + if(requestEndPos != std::string::npos) + { + response.append(buffer, requestEndPos + 1); + delete[] buffer; - response.append(buffer, readBytes); - } + return response; + } + } - return response; + response.append(buffer, readBytes); + } + + return response; } bool SerialSimulator::write(const std::string& data) { - ssize_t writtenBytes = ::write(ptmx, data.c_str(), data.length()); - return (writtenBytes != -1 && std::size_t(writtenBytes) == data.length()); + ssize_t writtenBytes = ::write(ptmx, data.c_str(), data.length()); + return writtenBytes != -1 && std::size_t(writtenBytes) == data.length(); } diff --git a/tests/src/simulators/simulator.cpp b/tests/src/simulators/simulator.cpp index 8227ebd..845f840 100644 --- a/tests/src/simulators/simulator.cpp +++ b/tests/src/simulators/simulator.cpp @@ -22,31 +22,31 @@ #include "simulators/simulator.hpp" Simulator::Simulator(const std::string& filePath) : - log(filePath) + log(filePath) { } Simulator::Simulator(std::iostream& stream) : - log(stream) + log(stream) { } bool Simulator::run() { - bool status = false; - while(isRunning()) - { - status = true; + bool status = false; + while(isRunning()) + { + status = true; - std::string logCommand; - std::string logResponse = log.read(logCommand); - if(log.isEnd()) break; + std::string logCommand; + std::string logResponse = log.read(logCommand); + if(log.isEnd()) break; - std::string devCommand = read(); - if(logCommand != devCommand) return false; + std::string devCommand = read(); + if(logCommand != devCommand) return false; - if(!write(devCommand + logResponse)) return false; - } + if(!write(devCommand + logResponse)) return false; + } - return status; + return status; } diff --git a/tests/src/simulators/socketsimulator.cpp b/tests/src/simulators/socketsimulator.cpp index b62fa02..d9256f3 100644 --- a/tests/src/simulators/socketsimulator.cpp +++ b/tests/src/simulators/socketsimulator.cpp @@ -26,25 +26,27 @@ #include "regilo/utils.hpp" -SocketSimulator::SocketSimulator(const std::string& filePath, unsigned short port) : Simulator(filePath), - acceptor(ioService, bai::tcp::endpoint(bai::tcp::v4(), port)), - socket(ioService), - socketIStream(&socketIStreamBuffer), - socketOStream(&socketOStreamBuffer) +SocketSimulator::SocketSimulator(const std::string& filePath, unsigned short port) : + Simulator(filePath), + acceptor(ioService, bai::tcp::endpoint(bai::tcp::v4(), port)), + socket(ioService), + socketIStream(&socketIStreamBuffer), + socketOStream(&socketOStreamBuffer) { } -SocketSimulator::SocketSimulator(std::iostream& stream, unsigned short port) : Simulator(stream), - acceptor(ioService, bai::tcp::endpoint(bai::tcp::v4(), port)), - socket(ioService), - socketIStream(&socketIStreamBuffer), - socketOStream(&socketOStreamBuffer) +SocketSimulator::SocketSimulator(std::iostream& stream, unsigned short port) : + Simulator(stream), + acceptor(ioService, bai::tcp::endpoint(bai::tcp::v4(), port)), + socket(ioService), + socketIStream(&socketIStreamBuffer), + socketOStream(&socketOStreamBuffer) { } SocketSimulator::~SocketSimulator() { - stop(); + stop(); } void SocketSimulator::start() @@ -53,50 +55,50 @@ void SocketSimulator::start() void SocketSimulator::stop() { - if(isRunning()) acceptor.close(); + if(isRunning()) acceptor.close(); } bool SocketSimulator::isRunning() const { - return (acceptor.is_open() && socket.is_open()); + return acceptor.is_open() && socket.is_open(); } std::string SocketSimulator::getEndpoint() const { - return "127.0.0.1:" + std::to_string(acceptor.local_endpoint().port()); + return "127.0.0.1:" + std::to_string(acceptor.local_endpoint().port()); } bool SocketSimulator::run() { - acceptor.accept(socket); - return Simulator::run(); + acceptor.accept(socket); + return Simulator::run(); } std::string SocketSimulator::read() { - std::string response; + std::string response; - boost::system::error_code errorCode; - boost::asio::read_until(socket, socketIStreamBuffer, requestEnd, errorCode); + boost::system::error_code errorCode; + boost::asio::read_until(socket, socketIStreamBuffer, requestEnd, errorCode); - if(errorCode == boost::asio::error::eof) return ""; + if(errorCode == boost::asio::error::eof) return ""; - regilo::getLine(socketIStream, response, requestEnd); + regilo::getLine(socketIStream, response, requestEnd); - return response + requestEnd; + return response + requestEnd; } bool SocketSimulator::write(const std::string& data) { - socketOStream << data; - - try - { - size_t writtenBytes = boost::asio::write(socket, socketOStreamBuffer); - return (writtenBytes == data.length()); - } - catch(boost::system::system_error&) - { - return false; - } + socketOStream << data; + + try + { + size_t writtenBytes = boost::asio::write(socket, socketOStreamBuffer); + return writtenBytes == data.length(); + } + catch(boost::system::system_error&) + { + return false; + } } diff --git a/tests/src/suites/hokuyocontrollersuite.cpp b/tests/src/suites/hokuyocontrollersuite.cpp index 77eba95..2c42915 100644 --- a/tests/src/suites/hokuyocontrollersuite.cpp +++ b/tests/src/suites/hokuyocontrollersuite.cpp @@ -39,40 +39,40 @@ template struct HokuyoControllerFixture { - std::string logPath = "data/hokuyo-log-scan-version.txt"; - std::string timedLogPath = "data/hokuyo-timed-log.txt"; - std::stringstream logStream; - - std::vector controllers; - - std::string correctScan; - std::map correctVersion; - - HokuyoControllerFixture() : - logStream("type log\nversion 2\n\nc 5 CMD1\n\nr 9 RESPONSE1\n\n") - { - controllers.emplace_back(new HokuyoController()); - controllers.emplace_back(new HokuyoController(logPath)); - controllers.emplace_back(new HokuyoController(logStream)); - - std::ifstream dataFile("data/hokuyo-correct-scan.txt"); - std::getline(dataFile, correctScan, '\0'); - - correctVersion["VEND"] = "Hokuyo Automatic Co.,Ltd."; - correctVersion["PROD"] = "SOKUIKI Sensor URG-04LX"; - correctVersion["FIRM"] = "3.3.00,08/04/16(20-4095[mm],240[deg],44-725[step],600[rpm])"; - correctVersion["PROT"] = "00003,(SCIP 1.0)"; - correctVersion["SERI"] = "H0713090"; - correctVersion["STAT"] = "FW Normal[FinalDist with shadow ]"; - } - - ~HokuyoControllerFixture() - { - for(HokuyoController *controller : controllers) - { - delete controller; - } - } + std::string logPath = "data/hokuyo-log-scan-version.txt"; + std::string timedLogPath = "data/hokuyo-timed-log.txt"; + std::stringstream logStream; + + std::vector controllers; + + std::string correctScan; + std::map correctVersion; + + HokuyoControllerFixture() : + logStream("type log\nversion 2\n\nc 5 CMD1\n\nr 9 RESPONSE1\n\n") + { + controllers.emplace_back(new HokuyoController()); + controllers.emplace_back(new HokuyoController(logPath)); + controllers.emplace_back(new HokuyoController(logStream)); + + std::ifstream dataFile("data/hokuyo-correct-scan.txt"); + std::getline(dataFile, correctScan, '\0'); + + correctVersion["VEND"] = "Hokuyo Automatic Co.,Ltd."; + correctVersion["PROD"] = "SOKUIKI Sensor URG-04LX"; + correctVersion["FIRM"] = "3.3.00,08/04/16(20-4095[mm],240[deg],44-725[step],600[rpm])"; + correctVersion["PROT"] = "00003,(SCIP 1.0)"; + correctVersion["SERI"] = "H0713090"; + correctVersion["STAT"] = "FW Normal[FinalDist with shadow ]"; + } + + ~HokuyoControllerFixture() + { + for(HokuyoController *controller : controllers) + { + delete controller; + } + } }; typedef boost::mpl::vector HokuyoControllers; @@ -81,101 +81,101 @@ BOOST_AUTO_TEST_SUITE(HokuyoControllerSuite) BOOST_FIXTURE_TEST_CASE_TEMPLATE(HokuyoControllerConstructorValues, HokuyoController, HokuyoControllers, HF) { - for(HokuyoController *controller : HF::controllers) - { - BOOST_CHECK_EQUAL(controller->RESPONSE_END, "\n\n"); - } + for(HokuyoController *controller : HF::controllers) + { + BOOST_CHECK_EQUAL(controller->RESPONSE_END, "\n\n"); + } } BOOST_FIXTURE_TEST_CASE_TEMPLATE(HokuyoControllerScanFromDevice, HokuyoController, HokuyoControllers, HF) { - std::mutex mutex; - mutex.lock(); + std::mutex mutex; + mutex.lock(); - std::string deviceEndpoint; - bool deviceStatus = false; - std::thread deviceThread([this, &deviceEndpoint, &mutex, &deviceStatus] () - { - Simulator *simulator = nullptr; - if(std::is_same::value) - { - simulator = new SerialSimulator(HF::logPath); - } - else if(std::is_same::value) - { - simulator = new SocketSimulator(HF::logPath, 12345); - } + std::string deviceEndpoint; + bool deviceStatus = false; + std::thread deviceThread([this, &deviceEndpoint, &mutex, &deviceStatus] () + { + Simulator *simulator = nullptr; + if(std::is_same::value) + { + simulator = new SerialSimulator(HF::logPath); + } + else if(std::is_same::value) + { + simulator = new SocketSimulator(HF::logPath, 12345); + } - simulator->responseEnd = "\n\n"; + simulator->responseEnd = "\n\n"; - BOOST_REQUIRE(simulator != nullptr); + BOOST_REQUIRE(simulator != nullptr); - simulator->start(); - deviceEndpoint = simulator->getEndpoint(); - mutex.unlock(); + simulator->start(); + deviceEndpoint = simulator->getEndpoint(); + mutex.unlock(); - deviceStatus = simulator->run(); - mutex.lock(); + deviceStatus = simulator->run(); + mutex.lock(); - delete simulator; - }); + delete simulator; + }); - HokuyoController *controller = HF::controllers.at(0); + HokuyoController *controller = HF::controllers.at(0); - mutex.lock(); - controller->connect(deviceEndpoint); + mutex.lock(); + controller->connect(deviceEndpoint); - BOOST_REQUIRE(controller->isConnected()); + BOOST_REQUIRE(controller->isConnected()); - regilo::ScanData scandata = controller->getScan(); - std::ostringstream scanStream; - scanStream << scandata; + regilo::ScanData scandata = controller->getScan(); + std::ostringstream scanStream; + scanStream << scandata; - BOOST_CHECK_EQUAL(scanStream.str(), HF::correctScan); + BOOST_CHECK_EQUAL(scanStream.str(), HF::correctScan); - std::map version = controller->getVersionInfo(); - BOOST_CHECK(version == HF::correctVersion); + std::map version = controller->getVersionInfo(); + BOOST_CHECK(version == HF::correctVersion); - mutex.unlock(); + mutex.unlock(); - if(deviceThread.joinable()) deviceThread.join(); + if(deviceThread.joinable()) deviceThread.join(); - BOOST_CHECK(deviceStatus); + BOOST_CHECK(deviceStatus); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(HokuyoControllerScanFromLog, HokuyoController, HokuyoControllers, HF) { - HokuyoController *controller = HF::controllers.at(1); + HokuyoController *controller = HF::controllers.at(1); - regilo::ScanData scanData = controller->getScan(false); - std::ostringstream scanStream; - scanStream << scanData; + regilo::ScanData scanData = controller->getScan(false); + std::ostringstream scanStream; + scanStream << scanData; - BOOST_CHECK_EQUAL(scanStream.str(), HF::correctScan); + BOOST_CHECK_EQUAL(scanStream.str(), HF::correctScan); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(HokuyoControllerScanFromTimedLog, HokuyoController, HokuyoControllers, HF) { - HokuyoController *controller = HF::controllers.at(0); - auto timedLog = std::make_shared>(HF::timedLogPath); - controller->setLog(timedLog); + HokuyoController *controller = HF::controllers.at(0); + auto timedLog = std::make_shared>(HF::timedLogPath); + controller->setLog(timedLog); - regilo::ScanData scanData = controller->getScan(false); - std::ostringstream scanStream; - scanStream << scanData; + regilo::ScanData scanData = controller->getScan(false); + std::ostringstream scanStream; + scanStream << scanData; - BOOST_CHECK_EQUAL(scanStream.str(), HF::correctScan); + BOOST_CHECK_EQUAL(scanStream.str(), HF::correctScan); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(HokuyoControllerSetScanParameters, HokuyoController, HokuyoControllers, HF) { - HokuyoController *controller = HF::controllers.at(0); + HokuyoController *controller = HF::controllers.at(0); - BOOST_CHECK_NO_THROW(controller->setScanParameters(50, 80, 1)); - BOOST_CHECK_THROW(controller->setScanParameters(800, 900, 1), std::invalid_argument); - BOOST_CHECK_THROW(controller->setScanParameters(50, 800, 1), std::invalid_argument); - BOOST_CHECK_THROW(controller->setScanParameters(50, 80, 100), std::invalid_argument); - BOOST_CHECK_THROW(controller->setScanParameters(80, 50, 1), std::invalid_argument); + BOOST_CHECK_NO_THROW(controller->setScanParameters(50, 80, 1)); + BOOST_CHECK_THROW(controller->setScanParameters(800, 900, 1), std::invalid_argument); + BOOST_CHECK_THROW(controller->setScanParameters(50, 800, 1), std::invalid_argument); + BOOST_CHECK_THROW(controller->setScanParameters(50, 80, 100), std::invalid_argument); + BOOST_CHECK_THROW(controller->setScanParameters(80, 50, 1), std::invalid_argument); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/src/suites/logsuite.cpp b/tests/src/suites/logsuite.cpp index 58a4dbe..ae25a2b 100644 --- a/tests/src/suites/logsuite.cpp +++ b/tests/src/suites/logsuite.cpp @@ -31,259 +31,265 @@ class StringNameLog : public regilo::Log { public: - std::string commandName = "command"; - char responseName = 'r'; + std::string commandName = "command"; + char responseName = 'r'; - using Log::Log; - virtual ~StringNameLog() = default; + using Log::Log; + virtual ~StringNameLog() = default; - virtual std::string readData(std::string& logCommand); + virtual std::string readData(std::string& logCommand); }; std::string StringNameLog::readData(std::string& logCommand) { - logCommand = readNameValue(stream, commandName); - std::string response = readNameValue(stream, responseName); + logCommand = readNameValue(stream, commandName); + std::string response = readNameValue(stream, responseName); - return response; + return response; } struct LogFixture { - std::string logPath = "data/hokuyo-log.txt"; - std::string timedLogPath = "data/hokuyo-timed-log.txt"; - std::stringstream logStream; - std::stringstream timedLogStream; - std::stringstream commentStream; - std::stringstream stringNameStream; - - regilo::Log *fileLog; - regilo::Log *streamLog; - regilo::Log *commentLog; - StringNameLog *stringNameLog; - - regilo::TimedLog *timedFileLog; - regilo::TimedLog *timedStreamLog; - - std::vector logs; - - LogFixture() : - logStream("type log\nversion 2\n\nc 10 G00076801\n\nr 22 0\n0C0C0C0C0C0C0C0C0C0C\n\nc 2 V\n\nr 10 0\nVERSION1\n\nc 10 G00076801\n\nr 22 0\n0C0C0C0C0C0C0C0C0C0C\n\nc 2 V\n\nr 10 0\nVERSION2\n\n"), - timedLogStream("type timedlog\nversion 2\ntimeres 1 1000000000\n\nc 10 G00076801\n\nr 22 0\n0C0C0C0C0C0C0C0C0C0C\nt 103203758\n\nc 2 V\n\nr 10 0\nVERSION1\nt 103203759\n\nc 10 G00076801\n\nr 22 0\n0C0C0C0C0C0C0C0C0C0C\nt 103203760\n\nc 2 V\n\nr 10 0\nVERSION2\nt 103203761\n\n"), - commentStream("# First line comment\ntype log\n# Comment in metadata\nversion 2\n\nc 2 V\n\n# Comment in data\nr 2 2\n\n\nc 11 missing_nl\n\nr 1 \n\nc 2 C\n\nr 2 R\n\n\n"), - stringNameStream("type stringlog\nversion 2\n\n# Comment 2 in string-name log\ncommand 8 getscan\n\n# Comment 2 in string-name log\nr 2 2\n\n\n"), - fileLog(new regilo::Log(logPath)), - streamLog(new regilo::Log(logStream)), - commentLog(new regilo::Log(commentStream)), - stringNameLog(new StringNameLog(stringNameStream)), - timedFileLog(new regilo::TimedLog(timedLogPath)), - timedStreamLog(new regilo::TimedLog(timedLogStream)) - { - logs.push_back(fileLog); - logs.push_back(streamLog); - logs.push_back(timedFileLog); - logs.push_back(timedStreamLog); - } - - ~LogFixture() - { - for(regilo::ILog *log : logs) - { - delete log; - } - } + std::string logPath = "data/hokuyo-log.txt"; + std::string timedLogPath = "data/hokuyo-timed-log.txt"; + std::stringstream logStream; + std::stringstream timedLogStream; + std::stringstream commentStream; + std::stringstream stringNameStream; + + regilo::Log *fileLog; + regilo::Log *streamLog; + regilo::Log *commentLog; + StringNameLog *stringNameLog; + + regilo::TimedLog *timedFileLog; + regilo::TimedLog *timedStreamLog; + + std::vector logs; + + __attribute__((annotate("oclint:suppress[long line]"))) + LogFixture() : + logStream("type log\nversion 2\n\nc 10 G00076801\n\nr 22 0\n0C0C0C0C0C0C0C0C0C0C\n\nc 2 V\n\nr 10 0\nVERSION1\n\nc 10 G00076801\n\nr 22 0\n0C0C0C0C0C0C0C0C0C0C\n\nc 2 V\n\nr 10 0\nVERSION2\n\n"), + timedLogStream("type timedlog\nversion 2\ntimeres 1 1000000000\n\nc 10 G00076801\n\nr 22 0\n0C0C0C0C0C0C0C0C0C0C\nt 103203758\n\nc 2 V\n\nr 10 0\nVERSION1\nt 103203759\n\nc 10 G00076801\n\nr 22 0\n0C0C0C0C0C0C0C0C0C0C\nt 103203760\n\nc 2 V\n\nr 10 0\nVERSION2\nt 103203761\n\n"), + commentStream("# First line comment\ntype log\n# Comment in metadata\nversion 2\n\nc 2 V\n\n# Comment in data\nr 2 2\n\n\nc 11 missing_nl\n\nr 1 \n\nc 2 C\n\nr 2 R\n\n\n"), + stringNameStream("type stringlog\nversion 2\n\n# Comment 2 in string-name log\ncommand 8 getscan\n\n# Comment 2 in string-name log\nr 2 2\n\n\n"), + fileLog(new regilo::Log(logPath)), + streamLog(new regilo::Log(logStream)), + commentLog(new regilo::Log(commentStream)), + stringNameLog(new StringNameLog(stringNameStream)), + timedFileLog(new regilo::TimedLog(timedLogPath)), + timedStreamLog(new regilo::TimedLog(timedLogStream)) + { + logs.push_back(fileLog); + logs.push_back(streamLog); + logs.push_back(timedFileLog); + logs.push_back(timedStreamLog); + } + + ~LogFixture() + { + for(regilo::ILog *log : logs) + { + delete log; + } + } }; BOOST_AUTO_TEST_SUITE(LogSuite) BOOST_FIXTURE_TEST_CASE(LogConstructorValues, LogFixture) { - BOOST_CHECK(fileLog->getFilePath() == logPath); - BOOST_CHECK(&streamLog->getStream() == &logStream); - BOOST_CHECK(timedFileLog->getFilePath() == timedLogPath); - BOOST_CHECK(&timedStreamLog->getStream() == &timedLogStream); + BOOST_CHECK(fileLog->getFilePath() == logPath); + BOOST_CHECK(&streamLog->getStream() == &logStream); + BOOST_CHECK(timedFileLog->getFilePath() == timedLogPath); + BOOST_CHECK(&timedStreamLog->getStream() == &timedLogStream); } BOOST_FIXTURE_TEST_CASE(LogMetadata, LogFixture) { - std::string types[] = { "log", "timedlog" }; + std::string types[] = { "log", "timedlog" }; - for(std::size_t i = 0; i < 2; i++) - { - regilo::ILog *log = logs[2 * i + 1]; + for(std::size_t i = 0; i < 2; i++) + { + regilo::ILog *log = logs[2 * i + 1]; - BOOST_CHECK(log->getMetadata() == nullptr); + BOOST_CHECK(log->getMetadata() == nullptr); - log->readMetadata(); - const regilo::LogMetadata *metadata = log->getMetadata(); - BOOST_REQUIRE(metadata != nullptr); + log->readMetadata(); + const regilo::LogMetadata *metadata = log->getMetadata(); + BOOST_REQUIRE(metadata != nullptr); - BOOST_CHECK_EQUAL(metadata->getType(), types[i]); - BOOST_CHECK_EQUAL(metadata->getVersion(), 2); - } + BOOST_CHECK_EQUAL(metadata->getType(), types[i]); + BOOST_CHECK_EQUAL(metadata->getVersion(), 2); + } } BOOST_FIXTURE_TEST_CASE(LogRead, LogFixture) { - for(regilo::ILog *log : logs) - { - BOOST_REQUIRE(log->getStream()); - BOOST_CHECK_EQUAL(bool(log->getStream()), !log->isEnd()); - - std::string logCommand; - std::string logResponse = log->read(logCommand); - - BOOST_CHECK_EQUAL(logCommand, "G00076801\n"); - - BOOST_CHECK_EQUAL(logResponse.substr(0, 22), "0\n0C0C0C0C0C0C0C0C0C0C"); - - regilo::TimedLog *timedLog = dynamic_cast*>(log); - if(timedLog != nullptr) - { - BOOST_CHECK(timedLog->getLastCommandNanoseconds() == std::chrono::nanoseconds(103203758)); - BOOST_CHECK(timedLog->getLastCommandTime() == std::chrono::nanoseconds(103203758)); - BOOST_CHECK_EQUAL(timedLog->getLastCommandTimeAs().count(), 103); - } - - for(std::size_t i = 0; i < 6; i++) - { - log->read(); - } - - BOOST_CHECK(log->isEnd()); - BOOST_CHECK(bool(log->getStream()) == !log->isEnd()); - } + for(regilo::ILog *log : logs) + { + BOOST_REQUIRE(log->getStream()); + BOOST_CHECK_EQUAL(bool(log->getStream()), !log->isEnd()); + + std::string logCommand; + std::string logResponse = log->read(logCommand); + + BOOST_CHECK_EQUAL(logCommand, "G00076801\n"); + + BOOST_CHECK_EQUAL(logResponse.substr(0, 22), "0\n0C0C0C0C0C0C0C0C0C0C"); + + auto *timedLog = dynamic_cast*>(log); + if(timedLog != nullptr) + { + BOOST_CHECK(timedLog->getLastCommandNanoseconds() == std::chrono::nanoseconds(103203758)); + BOOST_CHECK(timedLog->getLastCommandTime() == std::chrono::nanoseconds(103203758)); + BOOST_CHECK_EQUAL(timedLog->getLastCommandTimeAs().count(), 103); + } + + for(std::size_t i = 0; i < 6; i++) + { + log->read(); + } + + BOOST_CHECK(log->isEnd()); + BOOST_CHECK(bool(log->getStream()) == !log->isEnd()); + } } BOOST_FIXTURE_TEST_CASE(LogReadStringName, LogFixture) { - std::string logCommand; - std::string response = stringNameLog->read(logCommand); + std::string logCommand; + std::string response = stringNameLog->read(logCommand); - BOOST_CHECK_EQUAL(logCommand, "getscan\n"); - BOOST_CHECK_EQUAL(response, "2\n"); + BOOST_CHECK_EQUAL(logCommand, "getscan\n"); + BOOST_CHECK_EQUAL(response, "2\n"); - const regilo::LogMetadata *metadata = stringNameLog->getMetadata(); - BOOST_REQUIRE(metadata != nullptr); + const regilo::LogMetadata *metadata = stringNameLog->getMetadata(); + BOOST_REQUIRE(metadata != nullptr); - BOOST_CHECK_EQUAL(metadata->getType(), "stringlog"); - BOOST_CHECK_EQUAL(metadata->getVersion(), 2); + BOOST_CHECK_EQUAL(metadata->getType(), "stringlog"); + BOOST_CHECK_EQUAL(metadata->getVersion(), 2); } BOOST_FIXTURE_TEST_CASE(LogSkipComments, LogFixture) { - std::string logCommand; - std::string response = commentLog->read(logCommand); + std::string logCommand; + std::string response = commentLog->read(logCommand); - BOOST_CHECK_EQUAL(logCommand, "V\n"); - BOOST_CHECK_EQUAL(response, "2\n"); + BOOST_CHECK_EQUAL(logCommand, "V\n"); + BOOST_CHECK_EQUAL(response, "2\n"); - const regilo::LogMetadata *metadata = commentLog->getMetadata(); - BOOST_REQUIRE(metadata != nullptr); + const regilo::LogMetadata *metadata = commentLog->getMetadata(); + BOOST_REQUIRE(metadata != nullptr); - BOOST_CHECK_EQUAL(metadata->getType(), "log"); - BOOST_CHECK_EQUAL(metadata->getVersion(), 2); + BOOST_CHECK_EQUAL(metadata->getType(), "log"); + BOOST_CHECK_EQUAL(metadata->getVersion(), 2); } BOOST_FIXTURE_TEST_CASE(LogReadMissingNewLine, LogFixture) { - std::string logCommand, response; - commentLog->read(logCommand); + std::string logCommand, response; + commentLog->read(logCommand); - BOOST_CHECK_THROW(response = commentLog->read(logCommand), regilo::InvalidLogException); + BOOST_CHECK_THROW(response = commentLog->read(logCommand), regilo::InvalidLogException); } BOOST_FIXTURE_TEST_CASE(LogReadWrongName, LogFixture) { - stringNameLog->responseName = 'w'; - BOOST_CHECK_THROW(stringNameLog->read(), regilo::InvalidLogException); + stringNameLog->responseName = 'w'; + BOOST_CHECK_THROW(stringNameLog->read(), regilo::InvalidLogException); - stringNameLog->commandName = "wrong"; - BOOST_CHECK_THROW(stringNameLog->read(), regilo::InvalidLogException); + stringNameLog->commandName = "wrong"; + BOOST_CHECK_THROW(stringNameLog->read(), regilo::InvalidLogException); } BOOST_AUTO_TEST_CASE(LogWrite) { - std::string contents[] = - { - "type log\nversion 2\n\nc 4 cmd1\nr 9 response1\n\nc 4 cmd2\nr 9 response2\n\n", - "type timedlog\nversion 2\ntimeres 1 1\n\nc 4 cmd1\nr 9 response1\nt 0\n\nc 4 cmd2\nr 9 response2\nt 0\n\n" - }; - regilo::ILog *logs[] = { new regilo::Log("log.txt"), new regilo::TimedLog("timed-log.txt") }; - - for(std::size_t i = 0; i < 2; i++) - { - regilo::ILog *log = logs[i]; - - BOOST_CHECK(log->getStream()); - if(log->getStream()) - { - log->write("cmd1", "response1"); - log->write("cmd2", "response2"); - } - log->close(); - - std::ifstream logFile(log->getFilePath()); - std::string content; - std::getline(logFile, content, '\0'); - BOOST_CHECK_EQUAL(content, contents[i]); - - std::remove(log->getFilePath().c_str()); - delete log; - } + std::string contents[] = + { + "type log\nversion 2\n\nc 4 cmd1\nr 9 response1\n\nc 4 cmd2\nr 9 response2\n\n", + "type timedlog\nversion 2\ntimeres 1 1\n\nc 4 cmd1\nr 9 response1\nt 0\n\nc 4 cmd2\nr 9 response2\nt 0\n\n" + }; + + regilo::ILog *logs[] = + { + new regilo::Log("log.txt"), + new regilo::TimedLog("timed-log.txt") + }; + + for(std::size_t i = 0; i < 2; i++) + { + regilo::ILog *log = logs[i]; + + BOOST_CHECK(log->getStream()); + if(log->getStream()) + { + log->write("cmd1", "response1"); + log->write("cmd2", "response2"); + } + log->close(); + + std::ifstream logFile(log->getFilePath()); + std::string content; + std::getline(logFile, content, '\0'); + BOOST_CHECK_EQUAL(content, contents[i]); + + std::remove(log->getFilePath().c_str()); + delete log; + } } BOOST_FIXTURE_TEST_CASE(LogReadCommand, LogFixture) { - for(std::size_t i = 1; i < logs.size(); i += 2) - { - regilo::ILog *streamLog = logs.at(i); - - std::string response1 = streamLog->readCommand("V"); - BOOST_CHECK_EQUAL(response1, "0\nVERSION1"); - - std::string logCommand; - std::string response2 = streamLog->readCommand("V", logCommand); - BOOST_CHECK_EQUAL(logCommand, "V\n"); - BOOST_CHECK_EQUAL(response2, "0\nVERSION2"); - } + for(std::size_t i = 1; i < logs.size(); i += 2) + { + regilo::ILog *streamLog = logs.at(i); + + std::string response1 = streamLog->readCommand("V"); + BOOST_CHECK_EQUAL(response1, "0\nVERSION1"); + + std::string logCommand; + std::string response2 = streamLog->readCommand("V", logCommand); + BOOST_CHECK_EQUAL(logCommand, "V\n"); + BOOST_CHECK_EQUAL(response2, "0\nVERSION2"); + } } BOOST_FIXTURE_TEST_CASE(TimedLogNonSyncRead, LogFixture) { - BOOST_REQUIRE(timedFileLog->getStream()); + BOOST_REQUIRE(timedFileLog->getStream()); - auto start = std::chrono::high_resolution_clock::now(); + auto start = std::chrono::high_resolution_clock::now(); - std::string logCommand; - while(!timedFileLog->isEnd()) - { - timedFileLog->read(logCommand); - } + std::string logCommand; + while(!timedFileLog->isEnd()) + { + timedFileLog->read(logCommand); + } - std::chrono::nanoseconds elapsed = std::chrono::high_resolution_clock::now() - start; - std::chrono::nanoseconds lastCommandNanoseconds = timedFileLog->getLastCommandNanoseconds(); + std::chrono::nanoseconds elapsed = std::chrono::high_resolution_clock::now() - start; + std::chrono::nanoseconds lastCommandNanoseconds = timedFileLog->getLastCommandNanoseconds(); - BOOST_CHECK(lastCommandNanoseconds > elapsed); + BOOST_CHECK(lastCommandNanoseconds > elapsed); } BOOST_FIXTURE_TEST_CASE(TimedLogSyncRead, LogFixture) { - BOOST_REQUIRE(timedFileLog->getStream()); - timedFileLog->syncTime(); + BOOST_REQUIRE(timedFileLog->getStream()); + timedFileLog->syncTime(); - auto start = std::chrono::high_resolution_clock::now(); + auto start = std::chrono::high_resolution_clock::now(); - std::string logCommand; - while(!timedFileLog->isEnd()) - { - timedFileLog->read(logCommand); - } + std::string logCommand; + while(!timedFileLog->isEnd()) + { + timedFileLog->read(logCommand); + } - std::chrono::nanoseconds elapsed = std::chrono::high_resolution_clock::now() - start; - std::chrono::nanoseconds lastCommandNanoseconds = timedFileLog->getLastCommandNanoseconds(); + std::chrono::nanoseconds elapsed = std::chrono::high_resolution_clock::now() - start; + std::chrono::nanoseconds lastCommandNanoseconds = timedFileLog->getLastCommandNanoseconds(); - BOOST_CHECK(lastCommandNanoseconds < elapsed); + BOOST_CHECK(lastCommandNanoseconds < elapsed); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/src/suites/neatocontrollersuite.cpp b/tests/src/suites/neatocontrollersuite.cpp index fb6d100..b8b950e 100644 --- a/tests/src/suites/neatocontrollersuite.cpp +++ b/tests/src/suites/neatocontrollersuite.cpp @@ -39,33 +39,33 @@ template struct NeatoControllerFixture { - std::string logPath = "data/neato-log-scan-move-time.txt"; - std::string timedLogPath = "data/neato-timed-log-scan-move-time.txt"; - std::stringstream logStream; - - std::vector controllers; - - std::string correctScan; - std::string correctTime = "Sunday 13:57:09"; - - NeatoControllerFixture() : - logStream("type log\nversion 2\n\nc 11 getldsscan\n\nr 13 AngleInDegre\n\n\n") - { - controllers.emplace_back(new NeatoController()); - controllers.emplace_back(new NeatoController(logPath)); - controllers.emplace_back(new NeatoController(logStream)); - - std::ifstream dataFile("data/neato-correct-scan.txt"); - std::getline(dataFile, correctScan, '\0'); - } - - ~NeatoControllerFixture() - { - for(NeatoController *controller : controllers) - { - delete controller; - } - } + std::string logPath = "data/neato-log-scan-move-time.txt"; + std::string timedLogPath = "data/neato-timed-log-scan-move-time.txt"; + std::stringstream logStream; + + std::vector controllers; + + std::string correctScan; + std::string correctTime = "Sunday 13:57:09"; + + NeatoControllerFixture() : + logStream("type log\nversion 2\n\nc 11 getldsscan\n\nr 13 AngleInDegre\n\n\n") + { + controllers.emplace_back(new NeatoController()); + controllers.emplace_back(new NeatoController(logPath)); + controllers.emplace_back(new NeatoController(logStream)); + + std::ifstream dataFile("data/neato-correct-scan.txt"); + std::getline(dataFile, correctScan, '\0'); + } + + ~NeatoControllerFixture() + { + for(NeatoController *controller : controllers) + { + delete controller; + } + } }; typedef boost::mpl::vector NeatoControllers; @@ -74,114 +74,112 @@ BOOST_AUTO_TEST_SUITE(NeatoControllerSuite) BOOST_FIXTURE_TEST_CASE_TEMPLATE(NeatoControllerConstructorValues, NeatoController, NeatoControllers, NF) { - for(NeatoController *controller : NF::controllers) - { - BOOST_CHECK_EQUAL(controller->RESPONSE_END, std::string(1, 0x1a)); - } + for(NeatoController *controller : NF::controllers) + { + BOOST_CHECK_EQUAL(controller->RESPONSE_END, std::string(1, 0x1a)); + } } BOOST_FIXTURE_TEST_CASE_TEMPLATE(NeatoControllerScanFromDevice, NeatoController, NeatoControllers, NF) { - std::mutex mutex; - mutex.lock(); + std::mutex mutex; + mutex.lock(); - std::string deviceEndpoint; - bool deviceStatus = false; - std::thread deviceThread([this, &deviceEndpoint, &mutex, &deviceStatus] () - { - Simulator *simulator = nullptr; - if(std::is_same::value) - { - simulator = new SerialSimulator(NF::logPath); - } - else if(std::is_same::value) - { - simulator = new SocketSimulator(NF::logPath, 12345); - } + std::string deviceEndpoint; + bool deviceStatus = false; + std::thread deviceThread([this, &deviceEndpoint, &mutex, &deviceStatus] () + { + Simulator *simulator = nullptr; + if(std::is_same::value) + { + simulator = new SerialSimulator(NF::logPath); + } + else if(std::is_same::value) + { + simulator = new SocketSimulator(NF::logPath, 12345); + } - simulator->responseEnd = std::string(1, 0x1a); + simulator->responseEnd = std::string(1, 0x1a); - BOOST_REQUIRE(simulator != nullptr); + BOOST_REQUIRE(simulator != nullptr); - simulator->start(); - deviceEndpoint = simulator->getEndpoint(); - mutex.unlock(); + simulator->start(); + deviceEndpoint = simulator->getEndpoint(); + mutex.unlock(); - deviceStatus = simulator->run(); - mutex.lock(); + deviceStatus = simulator->run(); + mutex.lock(); - delete simulator; - }); + delete simulator; + }); - NeatoController *controller = NF::controllers.at(0); + NeatoController *controller = NF::controllers.at(0); - mutex.lock(); - controller->connect(deviceEndpoint); + mutex.lock(); + controller->connect(deviceEndpoint); - BOOST_REQUIRE(controller->isConnected()); + BOOST_REQUIRE(controller->isConnected()); - BOOST_CHECK(!controller->getTestMode()); - BOOST_CHECK(!controller->getLdsRotation()); + BOOST_CHECK(!controller->getTestMode()); + BOOST_CHECK(!controller->getLdsRotation()); - controller->setTestMode(true); - controller->setLdsRotation(true); + controller->startScanner(); - BOOST_REQUIRE(controller->getTestMode()); - BOOST_REQUIRE(controller->getLdsRotation()); + BOOST_REQUIRE(controller->getTestMode()); + BOOST_REQUIRE(controller->getLdsRotation()); - regilo::ScanData scanData = controller->getScan(); - std::ostringstream scanStream; - scanStream << scanData; + regilo::ScanData scanData = controller->getScan(); + std::ostringstream scanStream; + scanStream << scanData; - BOOST_CHECK_EQUAL(scanStream.str(), NF::correctScan); + BOOST_CHECK_EQUAL(scanStream.str(), NF::correctScan); - controller->setMotor(100, 100, 50); - std::string time = controller->getTime(); - BOOST_CHECK_EQUAL(time, NF::correctTime); + controller->setMotor(100, 100, 50); + std::string time = controller->getTime(); + BOOST_CHECK_EQUAL(time, NF::correctTime); - controller->setLdsRotation(false); - controller->setTestMode(false); + controller->stopScanner(); - BOOST_CHECK(!controller->getTestMode()); - BOOST_CHECK(!controller->getLdsRotation()); + BOOST_CHECK(!controller->getTestMode()); + BOOST_CHECK(!controller->getLdsRotation()); - mutex.unlock(); + mutex.unlock(); - if(deviceThread.joinable()) deviceThread.join(); + if(deviceThread.joinable()) deviceThread.join(); - BOOST_CHECK(deviceStatus); + BOOST_CHECK(deviceStatus); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(NeatoControllerScanFromLog, NeatoController, NeatoControllers, NF) { - NeatoController *controller = NF::controllers.at(1); + NeatoController *controller = NF::controllers.at(1); - regilo::ScanData scanData = controller->getScan(false); - std::ostringstream scanStream; - scanStream << scanData; + regilo::ScanData scanData = controller->getScan(false); + std::ostringstream scanStream; + scanStream << scanData; - BOOST_CHECK_EQUAL(scanStream.str(), NF::correctScan); + BOOST_CHECK_EQUAL(scanStream.str(), NF::correctScan); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(NeatoControllerScanFromTimedLog, NeatoController, NeatoControllers, NF) { - NeatoController *controller = NF::controllers.at(0); - auto timedLog = std::make_shared>(NF::timedLogPath); - controller->setLog(timedLog); + NeatoController *controller = NF::controllers.at(0); + auto timedLog = std::make_shared>(NF::timedLogPath); + controller->setLog(timedLog); - regilo::ScanData scanData = controller->getScan(false); - std::ostringstream scanStream; - scanStream << scanData; + regilo::ScanData scanData = controller->getScan(false); + std::ostringstream scanStream; + scanStream << scanData; - BOOST_CHECK_EQUAL(scanStream.str(), NF::correctScan); + BOOST_CHECK_EQUAL(scanStream.str(), NF::correctScan); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(NeatoControllerWrongHeader, NeatoController, NeatoControllers, NF) { - NeatoController *controller = NF::controllers.at(2); + NeatoController *controller = NF::controllers.at(2); - regilo::ScanData scanData = controller->getScan(false); - BOOST_CHECK(scanData.empty()); + regilo::ScanData scanData = controller->getScan(false); + BOOST_CHECK(scanData.empty()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/src/suites/scanrecorddatasuite.cpp b/tests/src/suites/scanrecorddatasuite.cpp index d124408..688a2cb 100644 --- a/tests/src/suites/scanrecorddatasuite.cpp +++ b/tests/src/suites/scanrecorddatasuite.cpp @@ -19,6 +19,7 @@ * */ +#include #include #include @@ -28,85 +29,108 @@ struct ScanRecordDataFixture { - int id1 = 0; - double angle1 = 0.1; - double distance1 = 1342; - int intensity1 = 123; - int errorCode1 = 0; - bool error1 = false; - - int id2 = 1; - double angle2 = 0.2; - double distance2 = 1023.43; - int intensity2 = 9; - int errorCode2 = 3; - bool error2 = true; - - std::size_t scanId = 4; - double rotationSpeed = 25.6; - - regilo::ScanRecord record1; - regilo::ScanRecord record2; - - regilo::ScanData data; - - ScanRecordDataFixture() : - record1(id1, angle1, distance1, intensity1, errorCode1, error1), - record2(id2, angle2, distance2, intensity2, errorCode2, error2), - data(scanId, rotationSpeed) - { - data.push_back(record1); - data.push_back(record2); - } + int index1 = 0; + double angle1 = 0.1; + double distance1 = 1342; + int intensity1 = 123; + int errorCode1 = 0; + bool error1 = false; + + int index2 = 1; + double angle2 = 0.2; + double distance2 = 1023.43; + int intensity2 = 9; + int errorCode2 = 3; + bool error2 = true; + + std::size_t scanIndex= 4; + double rotationSpeed = 25.6; + + regilo::ScanRecord record1; + regilo::ScanRecord record2; + + regilo::ScanData data; + + ScanRecordDataFixture() : + record1(index1, angle1, distance1, intensity1, errorCode1, error1), + record2(index2, angle2, distance2, intensity2, errorCode2, error2), + data(scanIndex, rotationSpeed) + { + data.push_back(record1); + data.push_back(record2); + } }; BOOST_FIXTURE_TEST_SUITE(ScanRecordDataSuite, ScanRecordDataFixture) BOOST_AUTO_TEST_CASE(ScanRecordConstructorValues) { - BOOST_REQUIRE(record1.id == id1); - BOOST_REQUIRE(record1.angle == angle1); - BOOST_REQUIRE(record1.distance == distance1); - BOOST_REQUIRE(record1.intensity == intensity1); - BOOST_REQUIRE(record1.errorCode == errorCode1); - BOOST_REQUIRE(record1.error == error1); + BOOST_REQUIRE(record1.index == index1); + BOOST_REQUIRE(record1.angle == angle1); + BOOST_REQUIRE(record1.distance == distance1); + BOOST_REQUIRE(record1.intensity == intensity1); + BOOST_REQUIRE(record1.errorCode == errorCode1); + BOOST_REQUIRE(record1.error == error1); } BOOST_AUTO_TEST_CASE(ScanRecordPrint) { - std::ostringstream out, correct; - out << record1 << std::endl << record2 << std::endl; - - correct << "ScanRecord(" << id1 << ": " << angle1 * 180 * M_1_PI << "°; " << distance1 << "mm)" << std::endl; - correct << "ScanRecord(" << id2 << ": " << angle2 * 180 * M_1_PI << "°; " << distance2 << "mm; error)" << std::endl; - - BOOST_REQUIRE(out.str() == correct.str()); + std::ostringstream out, correct; + out << record1 << std::endl << record2 << std::endl; + + correct << "ScanRecord(" + << index1 << ": " + << angle1 * 180 * M_1_PI << "°; " + << distance1 << "mm)" + << std::endl; + + correct << "ScanRecord(" + << index2 << ": " + << angle2 * 180 * M_1_PI << "°; " + << distance2 << "mm; error)" + << std::endl; + + BOOST_REQUIRE(out.str() == correct.str()); } BOOST_AUTO_TEST_CASE(ScanDataDefaultValues) { - regilo::ScanData defaultData; + regilo::ScanData defaultData; - BOOST_REQUIRE(defaultData.scanId == std::size_t(-1)); - BOOST_REQUIRE(defaultData.rotationSpeed == double(-1)); + BOOST_REQUIRE(defaultData.index == std::size_t(-1)); + BOOST_REQUIRE(defaultData.rotationSpeed == double(-1)); } BOOST_AUTO_TEST_CASE(ScanDataConstructorValues) { - BOOST_REQUIRE(data.scanId == scanId); - BOOST_REQUIRE(data.rotationSpeed == rotationSpeed); + BOOST_REQUIRE(data.index == scanIndex); + BOOST_REQUIRE(data.rotationSpeed == rotationSpeed); } BOOST_AUTO_TEST_CASE(ScanDataPrint) { - std::ostringstream out, correct; - out << data; - - correct << "ScanData(" << scanId << ", " << rotationSpeed << ", " << 2 << ')' << std::endl; - correct << "ScanRecord(" << id1 << ": " << angle1 * 180 * M_1_PI << "°; " << distance1 << "mm)" << std::endl; - correct << "ScanRecord(" << id2 << ": " << angle2 * 180 * M_1_PI << "°; " << distance2 << "mm; error)" << std::endl; - - BOOST_REQUIRE(out.str() == correct.str()); + std::ostringstream out, correct; + out << data; + + correct << "ScanData(" + << scanIndex << ", " + << rotationSpeed << ", " + << 2 << ')' + << std::endl; + + correct << "ScanRecord(" + << index1 << ": " + << angle1 * 180 * M_1_PI << "°; " + << distance1 << "mm)" + << std::endl; + + correct << "ScanRecord(" + << index2 << ": " + << angle2 * 180 * M_1_PI << "°; " + << distance2 << "mm; error)" + << std::endl; + + BOOST_REQUIRE(out.str() == correct.str()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/src/suites/streamcontrollersuite.cpp b/tests/src/suites/streamcontrollersuite.cpp index 2567d47..259902a 100644 --- a/tests/src/suites/streamcontrollersuite.cpp +++ b/tests/src/suites/streamcontrollersuite.cpp @@ -40,19 +40,20 @@ template struct StreamControllerFixture { - std::string logPath = "data/hokuyo-log.txt"; - std::stringstream logStream; + std::string logPath = "data/hokuyo-log.txt"; + std::stringstream logStream; - std::vector controllers; + std::vector controllers; - StreamControllerFixture() : - logStream("type log\nversion 2\n\nc 5 CMD1\n\nr 10 RESPONSE1\n\n\nc 2 V\n\nr 10 RESPONSE2\n\n\nc 5 CMD3\n\nr 4 2.5\n\n\nc 8 CMD 4 5\n\nr 10 RESPONSE4\n\n\nc 5 CMD6\n\nr 2 5\n\n\n") - { - controllers.push_back(new StreamController(logPath)); - controllers.push_back(new StreamController(logStream)); - } + __attribute__((annotate("oclint:suppress[long line]"))) + StreamControllerFixture() : + logStream("type log\nversion 2\n\nc 5 CMD1\n\nr 10 RESPONSE1\n\n\nc 2 V\n\nr 10 RESPONSE2\n\n\nc 5 CMD3\n\nr 4 2.5\n\n\nc 8 CMD 4 5\n\nr 10 RESPONSE4\n\n\nc 5 CMD6\n\nr 2 5\n\n\n") + { + controllers.push_back(new StreamController(logPath)); + controllers.push_back(new StreamController(logStream)); + } - inline const StreamController* getFileController() const { return controllers.at(0); } + inline const StreamController* getFileController() const { return controllers.at(0); } }; typedef boost::mpl::vector StreamControllers; @@ -61,83 +62,83 @@ BOOST_AUTO_TEST_SUITE(StreamControllerSuite) BOOST_FIXTURE_TEST_CASE_TEMPLATE(StreamControllerConstructorValues, StreamController, StreamControllers, SF) { - BOOST_CHECK(SF::controllers.at(0)->getLog()->getFilePath() == SF::logPath); - BOOST_CHECK(&(SF::controllers.at(1)->getLog()->getStream()) == &(SF::logStream)); + BOOST_CHECK(SF::controllers.at(0)->getLog()->getFilePath() == SF::logPath); + BOOST_CHECK(&(SF::controllers.at(1)->getLog()->getStream()) == &(SF::logStream)); - const StreamController *constController = SF::getFileController(); - BOOST_CHECK(constController->getLog()->getFilePath() == SF::logPath); + const StreamController *constController = SF::getFileController(); + BOOST_CHECK(constController->getLog()->getFilePath() == SF::logPath); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(StreamControllerLog, StreamController, StreamControllers, SF) { - auto log = std::make_shared(SF::logPath); - SF::controllers.at(0)->setLog(log); + auto log = std::make_shared(SF::logPath); + SF::controllers.at(0)->setLog(log); - BOOST_CHECK(SF::controllers.at(0)->getLog()->getFilePath() == SF::logPath); + BOOST_CHECK(SF::controllers.at(0)->getLog()->getFilePath() == SF::logPath); } BOOST_FIXTURE_TEST_CASE_TEMPLATE(StreamControllerCommunication, StreamController, StreamControllers, SF) { - std::mutex mutex; - mutex.lock(); + std::mutex mutex; + mutex.lock(); - std::string deviceEndpoint; - bool deviceStatus = false; - std::thread deviceThread([this, &deviceEndpoint, &mutex, &deviceStatus] () - { - Simulator *simulator = nullptr; - if(std::is_same::value) - { - simulator = new SerialSimulator(SF::logStream); - } - else if(std::is_same::value) - { - simulator = new SocketSimulator(SF::logStream, 12345); - } + std::string deviceEndpoint; + bool deviceStatus = false; + std::thread deviceThread([this, &deviceEndpoint, &mutex, &deviceStatus] () + { + Simulator *simulator = nullptr; + if(std::is_same::value) + { + simulator = new SerialSimulator(SF::logStream); + } + else if(std::is_same::value) + { + simulator = new SocketSimulator(SF::logStream, 12345); + } - BOOST_REQUIRE(simulator != nullptr); + BOOST_REQUIRE(simulator != nullptr); - simulator->start(); - deviceEndpoint = simulator->getEndpoint(); - mutex.unlock(); + simulator->start(); + deviceEndpoint = simulator->getEndpoint(); + mutex.unlock(); - deviceStatus = simulator->run(); - mutex.lock(); + deviceStatus = simulator->run(); + mutex.lock(); - delete simulator; - }); + delete simulator; + }); - StreamController controller; + StreamController controller; - BOOST_CHECK(!controller.isConnected()); - BOOST_CHECK(controller.getEndpoint().empty()); + BOOST_CHECK(!controller.isConnected()); + BOOST_CHECK(controller.getEndpoint().empty()); - mutex.lock(); - controller.connect(deviceEndpoint); + mutex.lock(); + controller.connect(deviceEndpoint); - BOOST_REQUIRE(controller.isConnected()); - BOOST_CHECK_EQUAL(controller.getEndpoint(), deviceEndpoint); + BOOST_REQUIRE(controller.isConnected()); + BOOST_CHECK_EQUAL(controller.getEndpoint(), deviceEndpoint); - std::string response1 = ((regilo::IController*) &controller)->sendCommand("CMD1"); - BOOST_CHECK_EQUAL(response1, "RESPONSE1"); + std::string response1 = ((regilo::IController*) &controller)->sendCommand("CMD1"); + BOOST_CHECK_EQUAL(response1, "RESPONSE1"); - std::string response2 = controller.template sendCommand('V'); - BOOST_CHECK_EQUAL(response2, "RESPONSE2"); + std::string response2 = controller.template sendCommand('V'); + BOOST_CHECK_EQUAL(response2, "RESPONSE2"); - double response3 = controller.template sendCommand("CMD3"); - BOOST_CHECK_CLOSE(response3, 2.5, 0.00001); + double response3 = controller.template sendCommand("CMD3"); + BOOST_CHECK_CLOSE(response3, 2.5, 0.00001); - std::string response4 = controller.template sendCommand("CMD", 4, 5); - BOOST_CHECK_EQUAL(response4, "RESPONSE4"); + std::string response4 = controller.template sendCommand("CMD", 4, 5); + BOOST_CHECK_EQUAL(response4, "RESPONSE4"); - int response5 = controller.template sendFormattedCommand("CMD%d", 6); - BOOST_CHECK_EQUAL(response5, 5); + int response5 = controller.template sendFormattedCommand("CMD%d", 6); + BOOST_CHECK_EQUAL(response5, 5); - mutex.unlock(); + mutex.unlock(); - if(deviceThread.joinable()) deviceThread.join(); + if(deviceThread.joinable()) deviceThread.join(); - BOOST_CHECK(deviceStatus); + BOOST_CHECK(deviceStatus); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/src/suites/utilssuite.cpp b/tests/src/suites/utilssuite.cpp index ec3c355..17ae4d9 100644 --- a/tests/src/suites/utilssuite.cpp +++ b/tests/src/suites/utilssuite.cpp @@ -33,16 +33,16 @@ typedef boost::mpl::list(epochTimeBefore); + auto epochTimeBefore = std::chrono::system_clock::now().time_since_epoch(); + T timeBefore = std::chrono::duration_cast(epochTimeBefore); - T time = regilo::epoch(); + T time = regilo::epoch(); - auto epochTimeAfter = std::chrono::system_clock::now().time_since_epoch(); - T timeAfter = std::chrono::duration_cast(epochTimeAfter); + auto epochTimeAfter = std::chrono::system_clock::now().time_since_epoch(); + T timeAfter = std::chrono::duration_cast(epochTimeAfter); - BOOST_REQUIRE(timeBefore <= time); - BOOST_REQUIRE(timeAfter >= time); + BOOST_REQUIRE(timeBefore <= time); + BOOST_REQUIRE(timeAfter >= time); } BOOST_AUTO_TEST_SUITE_END()