From 5ba1509af2eb03af43cd5efeb4330e4fda6b1a2e Mon Sep 17 00:00:00 2001
From: Johann Mantel <j-mantel@gmx.net>
Date: Fri, 18 Jun 2021 12:53:09 +0200
Subject: [PATCH] add initialization and run methods

---
 .../drivers/SickLaserUnit/CMakeLists.txt      |  27 +-
 .../drivers/SickLaserUnit/SickLaserUnit.cpp   | 394 ++++++++++--------
 .../drivers/SickLaserUnit/SickLaserUnit.h     |  21 +
 3 files changed, 246 insertions(+), 196 deletions(-)

diff --git a/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt b/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt
index 6d65f022c..92c9e15b4 100644
--- a/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt
+++ b/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt
@@ -17,19 +17,19 @@ armarx_set_target("Library: ${LIB_NAME}")
 armarx_add_component(
     COMPONENT_LIBS
         # ArmarXCore
-        ArmarXCore
-        ## ArmarXCoreComponentPlugins  # For DebugObserver plugin.
-        # ArmarXGui
-        ## ArmarXGuiComponentPlugins  # For RemoteGui plugin.
-        # RobotAPI
-        RobotAPICore
-        ## RobotAPIInterfaces
-        ## RobotAPIComponentPlugins  # For ArViz and other plugins.
-
-        # This project
-        ## ${PROJECT_NAME}Interfaces  # For ice interfaces from this package.
-        # This component
-        ## SickLaserUnitInterfaces  # If you defined a component ice interface above.
+	ArmarXCore
+	## ArmarXCoreComponentPlugins  # For DebugObserver plugin.
+	# ArmarXGui
+	## ArmarXGuiComponentPlugins  # For RemoteGui plugin.
+	# RobotAPI
+	RobotAPICore
+	## RobotAPIInterfaces
+	## RobotAPIComponentPlugins  # For ArViz and other plugins.
+
+	# This project
+	## ${PROJECT_NAME}Interfaces  # For ice interfaces from this package.
+	# This component
+	## SickLaserUnitInterfaces  # If you defined a component ice interface above.
 
     SOURCES
         SickLaserUnit.cpp
@@ -61,6 +61,7 @@ armarx_add_component(
 
 # Add unit tests
 add_subdirectory(test)
+add_subdirectory(include/sick_scan_base)
 
 # Generate the application
 armarx_generate_and_add_component_executable(
diff --git a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp
index 4ee9c8b0b..b99a4169a 100644
--- a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp
+++ b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp
@@ -33,214 +33,242 @@ namespace armarx
 
     std::string protocolToString(SickLaserUnit::Protocol protocol)
     {
-	std::string protocolStr;
-
-	switch (protocol)
-	{
-	    case SickLaserUnit::Protocol::ASCII:
-		protocolStr = "ASCII";
-		break;
-	    case SickLaserUnit::Protocol::Binary:
-		protocolStr = "Binary";
-		break;
-	}
-	return modeStr;
+        std::string protocolStr;
+
+        switch (protocol)
+        {
+            case SickLaserUnit::Protocol::ASCII:
+                protocolStr = "ASCII";
+                break;
+            case SickLaserUnit::Protocol::Binary:
+                protocolStr = "Binary";
+                break;
+        }
+        return modeStr;
     }
 
     armarx::PropertyDefinitionsPtr SickLaserUnit::createPropertyDefinitions()
     {
-	armarx::PropertyDefinitionsPtr def =
-	    new ComponentPropertyDefinitions(getConfigIdentifier());
-	// Publish to a topic (passing the TopicListenerPrx).
-	// def->topic(myTopicListener);
-
-	// Subscribe to a topic (passing the topic name).
-	// def->topic<PlatformUnitListener>("MyTopic");
-
-	// Use (and depend on) another component (passing the ComponentInterfacePrx).
-	// def->component(myComponentProxy)
-
-	//communication parameters
-	def->optional(properties.hostname, "hostname", "Hostname of the LaserScanner");
-	def->optional(properties.newIpAddress, "newIpAddress", "New IP address for the LaserScanner");
-	def->optional(properties.port, "port", "port to use on the LaserScanner");
-	def->optional(properties.timelimit, "timelimit", "timelimit for communication");
-	def->optional(properties.subscribeDatagram, "subscribeDatagram", "subscribe to Datagram in communication or not");
-	def->optional(properties.protocol, "protocol", "Either use ASCII or Binary protocol")
-	.map(protocolToString(Protocol::ASCII), Protocol::ASCII)
-	.map(protocolToString(Protocol::Binary), Protocol::Binary);
-	def->optional(properties.sopasProtocolType, "sopasProtocolType", "Automatically set to true if the Scanner does not support ASCII communication");
-	//Scanner parameters
-	def->required(properties.scannerType, "scannerType", "Name of the LaserScanner");
-	def->optional(properties.deviceNumber, "deviceNumber", "number of the LaserScanner Device");
-	def->required(properties.rangeMin, "rangeMin", "minimum Range of the Scanner");
-	def->required(properties.rangeMax, "rangeMax", "maximum Range of the Scanner");
-	def->optional(properties.timeIncrement, "timeIncrement", "timeIncrement??");
-	//Additional configuration
-	def->optional(properties.emulSensor, "emulateSensor", "overwrite the default Settings and don't connect to Scanner");
-
-	return def;
+        armarx::PropertyDefinitionsPtr def =
+            new ComponentPropertyDefinitions(getConfigIdentifier());
+        // Publish to a topic (passing the TopicListenerPrx).
+        // def->topic(myTopicListener);
+
+        // Subscribe to a topic (passing the topic name).
+        // def->topic<PlatformUnitListener>("MyTopic");
+
+        // Use (and depend on) another component (passing the ComponentInterfacePrx).
+        // def->component(myComponentProxy)
+
+        //communication parameters
+        def->optional(properties.hostname, "hostname", "Hostname of the LaserScanner");
+        def->optional(properties.newIpAddress, "newIpAddress", "New IP address for the LaserScanner");
+        def->optional(properties.port, "port", "port to use on the LaserScanner");
+        def->optional(properties.timelimit, "timelimit", "timelimit for communication");
+        def->optional(properties.subscribeDatagram, "subscribeDatagram", "subscribe to Datagram in communication or not");
+        def->optional(properties.protocol, "protocol", "Either use ASCII or Binary protocol")
+        .map(protocolToString(Protocol::ASCII), Protocol::ASCII)
+        .map(protocolToString(Protocol::Binary), Protocol::Binary);
+        def->optional(properties.sopasProtocolType, "sopasProtocolType", "Automatically set to true if the Scanner does not support ASCII communication");
+        //Scanner parameters
+        def->required(properties.scannerType, "scannerType", "Name of the LaserScanner");
+        def->optional(properties.deviceNumber, "deviceNumber", "number of the LaserScanner Device");
+        def->required(properties.rangeMin, "rangeMin", "minimum Range of the Scanner");
+        def->required(properties.rangeMax, "rangeMax", "maximum Range of the Scanner");
+        def->optional(properties.timeIncrement, "timeIncrement", "timeIncrement??");
+        //Additional configuration
+        def->optional(properties.emulSensor, "emulateSensor", "overwrite the default Settings and don't connect to Scanner");
+
+        return def;
     }
 
     void SickLaserUnit::onInitComponent()
     {
-	// Topics and properties defined above are automagically registered.
-
-	// Keep debug observer data until calling `sendDebugObserverBatch()`.
-	// (Requies the armarx::DebugObserverComponentPluginUser.)
-	// setDebugObserverBatchModeEnabled(true);
-
-	ARMARX_INFO_S << "SickLaserUnit sagt Hallo Welt!";
-
-	bool useTCP = false;
-	if (properties.hostname != "")
-	{
-	    useTCP = true;
-	}
-	bool changeIP = false;
-	if (sNewIp != "")
-	{
-	    changeIP = true;
-	}
-	//scanner Parameters
-	sick_scan::SickGenericParser* parser = new sick_scan::SickGenericParser(properties.scannerType);
-	parser->set_range_min(properties.rangeMin);
-	parser->set_range_max(properties.rangeMax);
-	parser->set_time_increment(properties.timeIncrement);
-	char colaDialectId = 'A'; // A or B (Ascii or Binary)
-
-	if (properties.emulSensor)
-	{
-	    ARMARX_INFO("Found paraemter emulSensor overwriting default settings. Emulation: True\n");
-	}
-	switch (properties.protocol)
-	{
-	    case Protocol::ASCII:
-		if (parser->getCurrentParamPtr()->getNumberOfLayers() > 4)
-		{
-		    ARMARX_WARNING(
-			"This scanner type does not support ASCII communication.\n"
-			"Binary communication has been activated.\n"
-			"The parameter \"sopasProtocolType\" has been set to \"true\".");
-		    properties.sopasProtocolType = true;
-		    properties.protocol = Protocol::Binary;
-		}
-		else
-		{
-		    ARMARX_INFO("ASCII protocol activated");
-		}
-		break;
-	    case Protocol::Binary:
-		ARMARX_INFO("Binary protocol activated");
-		break;
-	    default:
-		ARMARX_WARNING("Unknown protocol type. Defaulting to Binary protocol.\n");
-		properties.protocol = Protocol::Binary;
-	}
-	if (properties.protocol == Protocol::ASCII)
-	{
-	    parser->getCurrentParamPtr()->setUseBinaryProtocol(false);
-	    colaDialectId = 'A';
-	}
-	else
-	{
-	    parser->getCurrentParamPtr()->setUseBinaryProtocol(true);
-	    colaDialectId = 'B';
-	}
+        // Topics and properties defined above are automagically registered.
+
+        // Keep debug observer data until calling `sendDebugObserverBatch()`.
+        // (Requies the armarx::DebugObserverComponentPluginUser.)
+        // setDebugObserverBatchModeEnabled(true);
+
+        ARMARX_INFO_S << "SickLaserUnit sagt Hallo Welt!";
+
+        if (properties.hostname != "")
+        {
+            useTCP = true;
+        }
+        if (sNewIp != "")
+        {
+            changeIP = true;
+        }
+        //scanner Parameters
+        parser = new sick_scan::SickGenericParser(properties.scannerType);
+        parser->set_range_min(properties.rangeMin);
+        parser->set_range_max(properties.rangeMax);
+        parser->set_time_increment(properties.timeIncrement);
+        char colaDialectId = 'A'; // A or B (Ascii or Binary)
+
+        if (properties.emulSensor)
+        {
+            ARMARX_INFO_S << "Found paraemter emulSensor overwriting default settings. Emulation: True";
+        }
+        switch (properties.protocol)
+        {
+            case Protocol::ASCII:
+                if (parser->getCurrentParamPtr()->getNumberOfLayers() > 4)
+                {
+                    ARMARX_WARNING(
+                        "This scanner type does not support ASCII communication.\n"
+                        "Binary communication has been activated.\n"
+                        "The parameter \"sopasProtocolType\" has been set to \"true\".");
+                    properties.sopasProtocolType = true;
+                    properties.protocol = Protocol::Binary;
+                }
+                else
+                {
+                    ARMARX_INFO_S << "ASCII protocol activated";
+                }
+                break;
+            case Protocol::Binary:
+                ARMARX_INFO_S << "Binary protocol activated";
+                break;
+            default:
+                ARMARX_WARNING_S << "Unknown protocol type. Defaulting to Binary protocol.";
+                properties.protocol = Protocol::Binary;
+        }
+        if (properties.protocol == Protocol::ASCII)
+        {
+            parser->getCurrentParamPtr()->setUseBinaryProtocol(false);
+            colaDialectId = 'A';
+        }
+        else
+        {
+            parser->getCurrentParamPtr()->setUseBinaryProtocol(true);
+            colaDialectId = 'B';
+        }
+        isSensorInitialized = false;
     }
 
     void SickLaserUnit::onConnectComponent()
     {
-	ARMARX_INFO("Start initialising scanner [Ip: %s] [Port: %s]", hostname.c_str(),
-		 port.c_str());
-	// attempt to connect/reconnect
-	delete s; // disconnect scanner
-	if (useTCP)
-	{
-	    s = new sick_scan::SickScanCommonTcp(hostname, port, timelimit, parser,
-						 colaDialectId);
-	}
-	else
-	{
-	    ROS_ERROR("TCP is not switched on. Probably hostname or port not set. Use "
-		      "roslaunch to start node.");
-	    exit(-1);
-	}
-
-	if (emulSensor)
-	{
-	    s->setEmulSensor(true);
-	}
-	result = s->init();
-
-	isInitialized = true;
-	signal(SIGINT,
-	       SIG_DFL); // change back to standard signal handler after initialising
-	if (result == sick_scan::ExitSuccess) // OK -> loop again
-	{
-	    if (changeIP)
-	    {
-		runState = scanner_finalize;
-	    }
-	    runState = scanner_run; // after initialising switch to run state
-	}
-	else
-	{
-	    runState = scanner_init; // If there was an error, try to restart scanner
-	}
-	// Do things after connecting to topics and components.
-
-	/* (Requies the armarx::DebugObserverComponentPluginUser.)
-	// Use the debug observer to log data over time.
-	// The data can be viewed in the ObserverView and the LivePlotter.
-	// (Before starting any threads, we don't need to lock mutexes.)
-	{
-	    setDebugObserverDatafield("numBoxes", properties.numBoxes);
-	    setDebugObserverDatafield("boxLayerName", properties.boxLayerName);
-	    sendDebugObserverBatch();
-	}
-	*/
-
-	/* (Requires the armarx::ArVizComponentPluginUser.)
-	// Draw boxes in ArViz.
-	// (Before starting any threads, we don't need to lock mutexes.)
-	drawBoxes(properties, arviz);
-	*/
-
-	/* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.)
-	// Setup the remote GUI.
-	{
-	    createRemoteGuiTab();
-	    RemoteGui_startRunningTask();
-	}
-	*/
+        initScanner();
+        // Do things after connecting to topics and components.
+
+        /* (Requies the armarx::DebugObserverComponentPluginUser.)
+        // Use the debug observer to log data over time.
+        // The data can be viewed in the ObserverView and the LivePlotter.
+        // (Before starting any threads, we don't need to lock mutexes.)
+        {
+            setDebugObserverDatafield("numBoxes", properties.numBoxes);
+            setDebugObserverDatafield("boxLayerName", properties.boxLayerName);
+            sendDebugObserverBatch();
+        }
+        */
+
+        /* (Requires the armarx::ArVizComponentPluginUser.)
+        // Draw boxes in ArViz.
+        // (Before starting any threads, we don't need to lock mutexes.)
+        drawBoxes(properties, arviz);
+        */
+
+        /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.)
+        // Setup the remote GUI.
+        {
+            createRemoteGuiTab();
+            RemoteGui_startRunningTask();
+        }
+        */
     }
 
     void SickLaserUnit::run()
     {
-	while (!task->isStopped())
-	{
-	    if (result == sick_scan::ExitSuccess) // OK -> loop again
-	    {
-		ros::spinOnce();
-		result = s->loopOnce();
-	    }
-	    else
-	    {
-		runState = scanner_finalize; // interrupt
-	    }
-	}
+        while (!task->isStopped())
+        {
+            switch (runState)
+            {
+                case RunState::scannerInit:
+                    initScanner();
+                    break;
+                case RunState::scannerRun:
+                    if (result == sick_scan::ExitSuccess) // OK -> loop again
+                    {
+                        result = scanner->loopOnce();
+                    }
+                    else
+                    {
+                        runState = RunState::scannerFinalize;
+                    }
+                    break;
+                case RunState::scannerFinalize:
+                    break;
+                default:
+                    ARMARX_ERROR_S << "Invalid run state in mail loop";
+                    break;
+            }
+        }
     }
 
-    void SickLaserUnit::onDisconnectComponent() {}
+    void SickLaserUnit::onDisconnectComponent()
+    {
+        ARMARX_INFO_S << "Disconnecting LaserScanner.";
+        if (scanner != NULL)
+        {
+            delete scanner;
+        }
+        if (parser != NULL)
+        {
+            delete parser;
+        }
+    }
 
     void SickLaserUnit::onExitComponent() {}
 
     std::string SickLaserUnit::getDefaultName() const
     {
-	return "SickLaserUnit";
+        return "SickLaserUnit";
     }
 
+    void SickLaserUnit::initScanner()
+    {
+        isSensorInitialized = false;
+        ARMARX_INFO("Start initialising scanner [Ip: %s] [Port: %s]", properties.hostname.c_str(),
+                    properties.port.c_str());
+        // attempt to connect/reconnect
+        delete scanner; // disconnect scanner
+        if (useTCP)
+        {
+            scanner = new sick_scan::SickScanCommonTcp(properties.hostname, properties.port, properties.timelimit, parser,
+                    colaDialectId);
+        }
+        else
+        {
+            ARMARX_ERROR("TCP is not switched on. Probably hostname or port not set.\n");
+            exit();
+        }
+
+        if (emulSensor)
+        {
+            scanner->setEmulSensor(true);
+        }
+        result = scanner->init();
+        isSensorInitialized = true;
+
+        if (result == sick_scan::ExitSuccess) // OK -> loop again
+        {
+            if (changeIP)
+            {
+                runState = RunState::scannerFinalize;
+            }
+            else
+            {
+                runState = RunState::scannerRun; // after initialising switch to run state
+            }
+
+        }
+        else
+        {
+            runState = RunState::scannerInit; // If there was an error, try to restart scanner
+        }
+    }
     /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.)
     void SickLaserUnit::createRemoteGuiTab()
     {
diff --git a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h
index b4233d8c9..81f8391e1 100644
--- a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h
+++ b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h
@@ -36,6 +36,11 @@
 
 #include <vector>
 
+#include 'include/sick_scan_base/include/sick_scan/sick_scan_common_tcp.h'
+
+#include 'include/sick_scan_base/include/sick_scan/sick_generic_parser.h'
+#include 'include/sick_scan_base/include/sick_scan/sick_generic_laser.h'
+
 namespace armarx
 {
 
@@ -63,6 +68,12 @@ namespace armarx
             ASCII,
             Binary
         };
+        enum class RunState
+        {
+            scannerInit,
+            scannerRun,
+            scannerFinalize
+        };
 
     protected:
         /// @see PropertyUser::createPropertyDefinitions()
@@ -80,6 +91,8 @@ namespace armarx
         /// @see armarx::ManagedIceObject::onExitComponent()
         void onExitComponent() override;
 
+        void initScanner();
+
         /* (Requires armarx::LightweightRemoteGuiComponentPluginUser.)
         /// This function should be called once in onConnect() or when you
         /// need to re-create the Remote GUI tab.
@@ -127,9 +140,17 @@ namespace armarx
         };
         Properties properties;
 
+        RunState runState;
+
+        bool useTcp = false;
+        bool changeIP = false;
         char colaDialectId = 'B';
+
         int result = sick_scan::ExitError;
         sick_scan::SickScanConfig cfg;
+        sick_scan::SickScanCommonTcp* scanner;
+        sick_scan::SickGenericParser* parser;
+        bool isSensorInitialized = false;
         /* Use a mutex if you access variables from different threads
          * (e.g. ice functions and RemoteGui_update()).
         std::mutex propertiesMutex;
-- 
GitLab