/*! @file
 *  @brief This file includes the driver of the MPIA motor controller.
 *
 * @author Frank Kittmann
 * @version 08.07.23
 * @date 2008.07.23
 */

#pragma once

/* $Header: https://svn.mpia.de/gulli/TwiceAsNice/branch/unstable/TwiceAsNice/basda-mocca/src/device/mpia/mocon/Module.h 15119 2018-02-13 18:44:27Z mathar $
*/


#include <fstream>
#include <core/Module.h>
#include <mocon/CommandIDs.h>
#include <mocon/Exception.h>
#include <mocon/Profile.h>
#include <Basda/Mocca/Constant.h>
#include <Basda/Device.h>
#include <Nice/Map.h>
#include <Nice/Map/NPoint.h>
#include <Basda/Mocca/PropertyName.h>
#include <Basda/Mocca/MPIA/PropertyName.h>

namespace Basda
{
    /**
     * @brief This is the implementation of the MoCon module commands.
     *
     * The MPIA electronic rack can keep up to 8 motor controller cards, which
     * can control up to 8 motors each. This class extends the MPIACoreModule
     * class with the functionality of the motor controller module.
     *
     * @author Frank Kittmann
     * @version 09.06.30
     * @date 2009.06.30
     *
     */
    class MoConModule : public Basda::MPIACoreModule
    {
        public:
            /**
             * @brief Constructor.
             */
            MoConModule(std::string _name,
                        Nice::JointPtr _config,
                        MPIACoreProtocolPtr _protocol);

            /**
             * @brief Destructor.
             */
            ~MoConModule()
            {
            }

            /**
             * @brief This method send the command string to the electronic.
             *
             * This method is set to public due to requests from Lorenzo Busoni.
             * BUT THE USER OF THIS METHOD TAKE OVER THE RESPONSIBILITY OF THE
             * CORRECT ERROR HANDLING.
             * THE DRIVER DOES NOT HAVE THE CONTROL OVER THAT DEVICE ANY MORE.
             *
             * @param _commandID  the command ID
             * @param _selectID   the sub command ID
             * @param _cardNo     the ID of the MPIA electronic card
             * @param _moduleNo   the ID of the device module
             * @param _parameter  the parameter as string
             * @param _numberOfLines the number of lines that might be read
             *
             * Hi Martin,
             *
             * that's exactly what I was thinking:
             * The use case is (real example from our experience):
             * we discover at the telescope that we need to continuously monitor a
             * given property (PropA) of the MoCon (obviously because of a
             * malfunctioning in the hardware!). Without this monitor, we will be
             * stuck. You can add the required functionality in the Mocca adding the
             * function getPropA: this requires 4 hours and the day is lost. The day
             * after you are stuck because you discover that you miss PropB, and the
             * day is lost again.
             * As an alternative, one can add the 2 lines below in the code (with a
             * comment: "1 10 0 = getPropA") and this requires 5 minutes. The day
             * after one can add  a similar line with 1 11 0. When you're back in
             * Europe you implement getPropA and getPropB in Mocca and you cleanup
             * the code removing the receiveResponseForComment
             *
             * Generally speaking I think it is a safe idea to have a generic
             * interface to access _EVERY_ possible functionality of a device,
             * because soon or later you'll need it. In the case of the Mocon it is
             * quite easy, a good compromise between living dangerously and wasting
             * too much time in the effort of a complete implementation of all the
             * MoCon commands.
             *
             * Lorenzo Busoni
             */
            void chat(const unsigned int _cardNo,
                      const unsigned int _commandID,
                      const unsigned int _moduleNo,
                      const unsigned int _selectID,
                      const std::string _parameter,
                      const int _numberOfLines);

            /**
             * @brief This method was requested by Lorenzo Busoni (lbusoni@arcetri.astro.it 02.03.2012)
             *
             * It supports a direct communication with the MoCon.
             * BUT THE USER OF THIS METHOD TAKE OVER THE RESPONSIBILITY OF THE
             * CORRECT ERROR HANDLING.
             * THE DRIVER DOES NOT HAVE THE CONTROL OVER THAT DEVICE ANY MORE.
             *
             * @param _ret the allocated memory for the command response
             *
             * @see chat
             */
            void dontParse(std::string &_ret);

            /**
             * @brief This method was requested by Lorenzo Busoni (lbusoni@arcetri.astro.it 02.03.2012)
             *
             * It supports a direct communication with the MoCon without to
             * parse the response.
             * BUT THE USER OF THIS METHOD TAKE OVER THE RESPONSIBILITY OF THE
             * CORRECT ERROR HANDLING.
             * THE DRIVER DOES NOT HAVE THE CONTROL OVER THAT DEVICE ANY MORE.
             *
             * @param _commandID   the command ID which is defined in the CommandIDs.h
             * @param _cardNo      the card number
             * @param _moduleNo    the module number
             * @param _ret         the allocated space for the returned data
             * @param _numberOfLines  This parameter limitates how many data
             *                        should be read from the Ethernet buffer.
             *                        All data are read if the value is -1.
             *
             * @return the return parameter is stored in _ret parameter.
             *
             * @see chat
             */
            void receiveDataRaw(const unsigned int _cardNo,
                                const unsigned int _commandID,
                                const unsigned int _moduleNo,
                                std::string &_ret,
                                const unsigned int _numberOfLines);

            /**
             * @brief With this method a value of the basic configuration can be changed.
             *
             * The basic setting consist of
             *
             * <table border="1">
             <tr> <th> SelectID                    </th> <th> Parameter                                        </th> </tr>
             <tr> <td> Profile                     </td> <td> 0=trapeze, 2=s-curve                             </td> </tr>
             <tr> <td> Steps/Counts per revolution </td> <td> 1..8192                                          </td> </tr>
             <tr> <td> Velocity                    </td> <td> 0.0115..81916250.0 (unit: revolution per minute) </td> </tr>
             <tr> <td> Start velocity              </td> <td> 0.0115..81916250.0 (unit: revolution per minute) </td> </tr>
             <tr> <td> Acceleration                </td> <td> 1717..2147483647 (unit: revolution per minute^2) </td> </tr>
             <tr> <td> Deceleration                </td> <td> 1717..2147483647 (unit: revolution per minute^2) </td> </tr>
             <tr> <td> Jerk                        </td> <td> 3930..2147483647 (unit: revolution per minute^3) </td> </tr>
             </table>
             *
             * @param _selectID is the ID to define the type of the _parameter
             * @param _parameter the configuration value
             *
             * @throw ::Basda::MoCon::CmdForStepperException
             * @throw ::Basda::MoCon::RevolutionNotDefinedException
             * @throw ::Basda::MoCon::MotorInMotionException
             *
             * @see MPIA/MoCon/CommandIDs.h - SelectBasicSettings
             */
            void setBasicSettings(const SelectBasicSettings::Constant _selectID,
                                  const double _parameter);

            /**
             * @brief This method sets all basic configuration with the values
             *        stored in the property tree.
             *
             * The basic configuration values are stored in the sub tree
             * CFG.DATASHEET.BASIC of the motor and can be configured via the
             * configuration files.
             */
            void setBasicSettings();

            /**
             * @brief This method returns the basic configuration of the motor.
             *
             * The basic settings will be stored in the properties:
             *
             *  - CFG.DATASHEET.BASIC.PROFILE
             *  - CFG.DATASHEET.BASIC.RESOLUTION
             *  - CFG.DATASHEET.BASIC.VELOCITY.STRAIGHT
             *  - CFG.DATASHEET.BASIC.VELOCITY.START
             *  - CFG.DATASHEET.BASIC.VELOCITY.ACCELERATION
             *  - CFG.DATASHEET.BASIC.VELOCITY.DECELERATION
             *  - CFG.DATASHEET.BASIC.JERK
             *
             * @throw ::Basda::MoCon::MotorNotInitializedException
             */
            void getBasicSettings(bool _compareParameter = false);

            void validateBasicSettings();

            /**
             * @brief With this method a value of the motor configuration can be changed.
             *
             * <table border="1">
             <tr> <th> SelectID                             </th> <th> Parameter                     </th> </tr>
             <tr> <td> Reference switch                     </td> <td> 0: disable (default)                         <br>
             1: positive limit switch                     <br>
             2: negative limit switch                     <br>
             3: separate switch                           <br>
             4: level switch                                   </td> </tr>
             <tr> <td> Reference sense                      </td> <td> 0: reference switch is high active (default) <br>
             1: reference switch is low active                 </td> </tr>
             <tr> <td> Home velocity                        </td> <td> 0.0115..81916250.0 (unit: revolution per minute)  </td> </tr>
             <tr> <td> Docking velocity                     </td> <td> 0.0115..81916250.0 (unit: revolution per minute)  </td> </tr>
             <tr> <td> Docking distance to reference switch </td> <td> 1..1000000000                                     </td> </tr>
             </table>
             *
             * @param _selectID is the ID to define the type of the _parameter
             * @param _parameter the configuration value
             *
             * @throw ::Basda::MoCon::RevolutionNotDefinedException
             * @throw ::Basda::MoCon::MotorInMotionException
             *
             * @see MPIA/MoCon/CommandIDs.h - SelectMotorSettings
             */
            void setMotorSettings(const SelectMotorSettings::Constant _selectID,
                                  const double _parameter);

            /**
             * @brief This method sets all motor configurations with the values
             *        stored in the property tree.
             *
             * The motor configuration values are stored in the sub tree
             * CFG.DATASHEET.MOTOR of the motor and can be configured via the
             * configuration files.
             */
            void setMotorSettings();

            /**
             * @brief This method returns the motor configuration.
             *
             * The motor settings will be stored in the properties:
             *
             * - CFG.DATASHEET.MOTOR.REFERENCE.SWITCH
             * - CFG.DATASHEET.MOTOR.REFERENCE.SENSE
             * - CFG.DATASHEET.MOTOR.VELOCITY.HOME
             * - CFG.DATASHEET.MOTOR.VELOCITY.DOCKING
             * - CFG.DATASHEET.MOTOR.DOCKING_DISTANCE
             *
             * @throw ::Basda::MoCon::MotorNotInitializedException
             */
            void getMotorSettings(bool _compareParameter = false);

            /**
             * @brief Returns the motor type
             *
             * @return 0 - servo (Basda::MotorType::SERVO) 1 - stepper (Basda::MotorType::STEPPER)
             */
            int getMotorType();

            /**
             * @brief With this method a value of the stepper settings can be changed.
             *
             * The stepper settings can be set only for stepper motors. The stepper settings are:
             *
             * <table border="1">
             <tr> <th> SelectID               </th> <th> Parameter                                 </th> </tr>
             <tr> <td> Micro steps            </td> <td> 1..x (maximum depending on the amplifier) </td> </tr>
             <tr> <td> Micro steps adaption   </td> <td> 0: disable, 1: enable                     </td> </tr>
             <tr> <td> Auto power off / break </td> <td> 0: disable, 1: enable                     </td> </tr>
             </table>
             *
             * Each step of a stepper motor is divided in microsteps. In the
             * default mode is the micro step adaption enabled and the motor
             * position will be adjusted to a full step. To move the motor in
             * micro steps the micro step adaption has to be disabled.
             * But note: The position value has to multiply with the micro steps
             * in order to reach the same position as without micro steps.
             * The auto power off parameter allows that the power will be switched
             * off automatically in order to reduce the waste heat.
             *
             * @param _selectID is the ID to define the type of the _parameter
             * @param _parameter the configuration value
             *
             * @throw ::Basda::MoCon::CmdForStepperException
             * @throw ::Basda::MoCon::MotorInMotionException
             *ERVO
             * @see MPIA/MoCon/CommandIDs.h - SelectStepperSettings
             */
            void setStepperSettings(const SelectStepperSettings::Constant _selectID,
                                    const int _parameter);

            /**
             * @brief This method sets all stepper settings with the values stored
             *        in the property tree.
             *
             * The stepper settings are stored in the sub tree CFG.DATASHEET.STEPPER
             * of the motor and can be configured via the configuration files.
             */
            void setStepperSettings();

            /**
             * @brief This method returns the stepper settings of the motor.
             *
             * The stepper settings will be stored in the properties:
             * - CFG.DATASHEET.STEPPER.MICROSTEPS.VALUE
             * - CFG.DATASHEET.STEPPER.MICROSTEPS.ADAPTION
             * - CFG.DATASHEET.STEPPER.AUTO_POWER_OFF
             *
             * @throw ::Basda::MoCon::CmdForStepperException
             */
            void getStepperSettings(bool _compareParameter = false);

            /**
             * @brief This method set the servo settings.
             *
             * The servo settings can be set only for servo motors. The servo settings are:
             *
             * <table border="1">
             <tr> <th> SelectID </th> <th> Parameter           </th> </tr>
             <tr> <td> KP       </td> <td> 0..32767            </td> </tr>
             <tr> <td> KI       </td> <td> 0..32767            </td> </tr>
             <tr> <td> KD       </td> <td> 0..32767            </td> </tr>
             <tr> <td> KAFF     </td> <td> 0..32767            </td> </tr>
             <tr> <td> KVFF     </td> <td> 0..32767            </td> </tr>
             <tr> <td> KOUT     </td> <td> 0..100 (unit: %)    </td> </tr>
             <tr> <td> ILIM     </td> <td> 0..2147483647       </td> </tr>
             <tr> <td> BIAS     </td> <td> -100..100 (unit: %) </td> </tr>
             <tr> <td> LIMIT    </td> <td> 0..100 (unit: %)    </td> </tr>
             </table>
             *
             * @param _selectID is the ID to define the type of the _parameter
             * @param _parameter the configuration value
             *
             * @throw ::Basda::MoCon::CmdForServoException
             * @throw ::Basda::MoCon::MotorInMotionException
             *
             * @see MPIA/MoCon/CommandIDs.h - SelectServoLoopSettings
             */
            void setServoLoopSettings(const SelectServoLoopSettings::Constant _selectID,
                                      const unsigned int _parameter);

            /**
             * @brief This method sets all servo settings with the values stored
             *        in the property tree.
             *
             * The servo settings are stored in the sub tree CFG.DATASHEET.SERVOLOOP
             * of the motor and can be configured via the configuration files.
             */
            void setServoLoopSettings();

            /**
             * @brief This method returns the servo settings of the motor.
             *
             * The servo settings will be stored in the properties:
             * - CFG.DATASHEET.SERVOLOOP.KP
             * - CFG.DATASHEET.SERVOLOOP.KI
             * - CFG.DATASHEET.SERVOLOOP.KD
             * - CFG.DATASHEET.SERVOLOOP.KAFF
             * - CFG.DATASHEET.SERVOLOOP.KVFF
             * - CFG.DATASHEET.SERVOLOOP.KOUT
             * - CFG.DATASHEET.SERVOLOOP.ILIM
             * - CFG.DATASHEET.SERVOLOOP.BIAS
             * - CFG.DATASHEET.SERVOLOOP.LIMIT
             *
             * @throw ::Basda::MoCon::CmdForServoException
             */
            void getServoLoopSettings(bool _compareParameter = false);

            /**
             * @brief With this method a value of the incremental encoder settings
             *        can be changed.
             *
             * The incremental encoder settings are:
             *
             * <table border="1">
             <tr> <th> SelectID                          </th> <th> Parameter                        </th> </tr>
             <tr> <td> incremental counts per revolution </td> <td> -32767..32767 (unit: counts/rev) </td> </tr>
             <tr> <td> steps per revolution              </td> <td> -32767..32767 (unit: steps/rev)  </td> </tr>
             <tr> <td> error limit                       </td> <td> 0..2147483647                    </td> </tr>
             </table>
             *
             * @param _selectID is the ID to define the type of the _parameter
             * @param _parameter the configuration value
             *
             * @throw ::Basda::MoCon::MotorInMotionException
             *
             * @see MPIA/MoCon/CommandIDs.h - SelectSetEncodeSettings
             */
            void setEncoderSettings(const SelectSetEncodeSettings::Constant _selectID,
                                    const int _parameter);

            /**
             * @brief This method sets all incremental encoder settings with the
             *        values stored in the property tree.
             *
             * The incremental encoder settings are stored in the sub tree
             * CFG.DATASHEET.ENCODER of the motor and can be configured via the
             * configuration files.
             */
            void setEncoderSettings();

            /**
             * @brief This method returns the incremental encoder settings.
             *
             * The incremental encoder settings will be stored in the properties:
             *
             * - CFG.DATASHEET.ENCODER.COUNTS
             * - CFG.DATASHEET.ENCODER.STEPS
             * - CFG.DATASHEET.ENCODER.ERROR_LIMIT
             *
             * @throw ::Basda::MoCon::MotorNotInitializedException
             */
            void getEncoderSettings(bool _compareParameter = false);

            /**
             * @brief With this method a value of the amplifier settings can be changed.
             *
             * The amplifier settings are:
             *
             * <table border="1">
             <tr> <th>SelectID                 </th> <th> Parameter 1                                          </th> <th> Parameter 2               </th> <th> Parameter 3          </th> </tr>
             <tr> <td>Sense control signal     </td> <td> bit 0: PWMa/Pulse     (0=not inverse, 1=inverse)<br>
             bit 1: PWMb           (0=not inverse, 1=inverse)<br>
             bit 2: PWMc/AtRest    (0=not inverse, 1=inverse)<br>
             bit 3: Sign/Dir       (0=not inverse, 1=inverse)<br>
             bit 4: power off      (0=not inverse, 1=inverse)<br>
             bit 5: auto power off (0=not inverse, 1=inverse)     </td> <td> -                         </td> <td> -                    </td> </tr>
             <tr> <td>Bit mask for microsteps  </td> <td> 0x0..0xFF                                            </td> <td> -                         </td> <td> -                    </td> </tr>
             <tr> <td>Microsteps and allocation</td> <td>16 different position: 1..16                          </td> <td> microstep value: 1..1024  </td> <td> bit value: 0x0..0xFF </td> </tr>
             </table>
             *
             * @param _selectID is the ID to define the type of the _parameter
             * @param _parameter1 the configuration value
             * @param _parameter2 the configuration value only for the Microsteps
             *                    and adaption option
             * @param _parameter3 the configuration value only for the Microsteps
             *                    and adaption option
             *
             * @throw ::Basda::MoCon::CmdForStepperException
             * @throw ::Basda::MoCon::MotorInMotionException
             *
             * @see MPIA/MoCon/CommandIDs.h - SelectAmplifierSettings
             */
            void setAmplifierSettings(const SelectAmplifierSettings::Constant _selectID,
                                      const int _parameter1,
                                      const int _parameter2 = -1,
                                      const int _parameter3 = -1);

            /**
             * @brief This method sets all amplifier settings with the values
             *        stored in the property tree.
             *
             * The amplifier settings are stored in the sub tree CFG.DATASHEET.AMPLIFIER
             * of the motor and can be configured via the configuration files.
             */
            void setAmplifierSettings();

            /**
             * @brief This method returns the amplifier configuration of the motor.
             *
             * The amplifier settings will be stored in the properties:
             *
             *  - VAR.AMPLIFIER.CARD.CLASSIFICATION
             *  - VAR.AMPLIFIER.CARD.IDENTIFICATION
             *  - VAR.AMPLIFIER.CARD.NAME
             *  - VAR.AMPLIFIER.CARD.VERSION
             *  - VAR.AMPLIFIER.CARD.MANUFACTURE_DATE
             *  - VAR.AMPLIFIER.CARD.SERIAL_NUMBER
             *  - VAR.AMPLIFIER.CARD.OFFSET
             *
             * @throw ::Basda::MoCon::AADException
             */
            void getAmplifierCardInfo();

            /**
             * @brief This method returns information of the amplifier.
             *
             * The amplifier settings will be stored in the properties:
             *
             * - VAR.AMPLIFIER.MODULE.CLASSIFICATION
             * - VAR.AMPLIFIER.MODULE.IDENTIFICATION
             * - VAR.AMPLIFIER.MODULE.NAME
             * - VAR.AMPLIFIER.MODULE.MOTOR_POWER_SUPPLY
             * - VAR.AMPLIFIER.MODULE.FUSE
             * - VAR.AMPLIFIER.MODULE.THERMAL_FLAG
             * - VAR.AMPLIFIER.MODULE.SHORT_CURRENT_FLAG
             * - VAR.AMPLIFIER.MODULE.PWMA
             * - VAR.AMPLIFIER.MODULE.PWMB
             * - VAR.AMPLIFIER.MODULE.PWMC
             * - VAR.AMPLIFIER.MODULE.SIGN_DIR_INVERSE
             * - VAR.AMPLIFIER.MODULE.BREAK_POWEROFF_INVERSE
             * - VAR.AMPLIFIER.MODULE.AUTO_POWEROFF_INVERSE
             *
             * @throw ::Basda::MoCon::AADException
             */
            void getAmplifierInfo();

            /**
             * @brief This method returns the firmware version of the motor controller.
             *
             * The firmware settings will be stored in the properties:
             *
             * - VAR.MC.TYPE
             * - VAR.MC.CONTROLLED_AXIS
             * - VAR.MC.VERSION
             *
             */
            void getMotorControllerVersion();

            /**
             * @brief This methods returns the motor controller error number.
             *
             * In some cases the motor controller returns a
             * Basda::MoCon::CheckSumException. This method read the error code
             * from the MoCon and stores it in the property
             *
             * - VAR.MC.ERROR
             *
             * @throw ::Basda::MoCon::CheckSumException
             *
             * @see Basda::MoCon::CheckSumException
             */
            std::string getMotorControllerErrorNr();

            /**
             * @brief This method try to initialized the motor If not all motor
             *        settings are available and valid a exception will be thrown.
             *
             * @throw ::Basda::MoCon::MotorInMotionException
             * @throw ::Basda::MoCon::ParamMissingException
             * @throw ::Basda::MoCon::NoAmpplifierException
             * @throw ::Basda::MoCon::MicrostepResolutionException
             * @throw ::Basda::MoCon::CheckSumException
             */
            void initializeMotor();

            /**
             * @brief This method stops the motor with a deceleration.
             */
            void stop();

            /**
             * @brief Abort the moving of the motor immediately without deceleration.
             *
             * @note Abrupt stop of a fast running motor can leads to losing steps.
             *       The motor could be damaged too.
             */
            void abort();

            /**
             * @brief The motor moves to the positive software limit switch.
             *
             * @param  _travelRangeCheck is true if the travel range might be
             *                           checked before the movement. In that case
             *                           the motor will move maximal to the software
             *                           limit.
             *                           If false the motor will move relative INT_MAX steps
             *
             * @return the maximal absolute position within the travel range
             *         (return value is required to calculate the completion value)
             */
            double moveToPositiveLimit(bool _travelRangeCheck = true);

            /**
             * @brief The motor moves to the negative software limit switch.
             *
             * @param  _travelRangeCheck is true if the travel range might be
             *                           checked before the movement. In that case
             *                           the motor will move maximal to the software
             *                           limit.
             *                           If false the motor will move relative INT_MAX steps
             *
             * @return the minimal absolute position within the travel range (return value is required to calculate the completion value)
             */
            double moveToNegativeLimit(bool _travelRangeCheck = true);

            /**
             * @brief The motor moves out of the limit switch.
             *
             * @return the docking distance (return value is required to calculate
             *         the completion value)
             */
            double moveOutOfLimit();

            /**
             * @brief The motor moves to the absolute position.
             *
             * The given absolute position will be checked if it is in the valid
             * travel range, before the command will be send to the motor controller.
             * Is the target position still in the valid travel range the absolute
             * position will be send to the motor controller. In case the target
             * position is out of the valid range, the position will be adjusted
             * to the maximum / minimum position.
             * The travel range can be set in the configuration file via the property
             *
             * - CFG.DATASHEET.TRAVELRANGE.
             *
             * The unit of the travel range property is steps/counts and hard-coded.
             *
             * @param _absolutePosition
             * @param _unit the unit in which the absolute position value is given
             *
             * @throw ::Basda::MoCon::MotorInMotionException
             * @throw ::Basda::MoCon::MotorNotInitializedException
             * @throw ::Basda::MoCon::MotorInPosLimitException
             * @throw ::Basda::MoCon::MotorInNegLimitException
             *
             * @see Unit, Basda::MoConModuleMoveAbsThread
             *
             * @todo remove the hardcoded travel range unit!
             */
            void moveAbsolute(int _absolutePosition);

            /**
             * @brief The motor moves to the relative position.
             *
             * The given relative position will be converted to a absolute position
             * value first to check if it is in the valid travel range. Is the target
             * position still in the valid travel range the relative position will
             * be send to the motor controller. In case the target position is
             * out of the valid range, the position will be adjusted to the
             * maximum valid relative position.
             * The travel range can be set in the configuration file via the property
             *
             * - CFG.DATASHEET.TRAVELRANGE.
             *
             * The unit of the travel range property is steps/counts and hard-coded.
             *
             * @param _relativePosition in steps
             * @param _unit the unit in which the absolute position value is given
             *
             * @throw ::Basda::MoCon::MotorInMotionException
             * @throw ::Basda::MoCon::MotorNotInitializedException
             * @throw ::Basda::MoCon::MotorInPosLimitException
             * @throw ::Basda::MoCon::MotorInNegLimitException
             *
             * @see Unit, Basda::MoConModuleMoveRelThread
             */
            void moveRelative(int _relativePosition);

            /**
             * @brief The motor is looking for the reference position. The motor
             *        controller reset the step counter to zero if the home
             *        position is found.
             *
             * @throw ::Basda::MoCon::MotorInMotionException
             * @throw ::Basda::MoCon::MotorNotInitializedException
             * @throw ::Basda::MoCon::MotorSettingsIncompleteException
             *
             * @see Basda::MoConModuleMoveHomeThread
             */
            void moveToHome();

            /**
             * @brief The lost steps can be corrected with this methods.
             *
             * The position register will be not changed!
             *
             * @throw ::Basda::MoCon::CmdForStepperException
             * @throw ::Basda::MoCon::MotorInMotionException
             * @throw ::Basda::MoCon::MotorNotInitializedException
             * @throw ::Basda::MoCon::MotorInPosLimitException
             * @throw ::Basda::MoCon::MotorInNegLimitException
             * @throw ::Basda::MoCon::IEncNotInitializedException
             */
            void moveCorrection();

#if 0
            /*
             * @brief The motion error event will be stored in the property,
             *        wchich will be checked by the status request of the servive.
             */
           bool checkMotionError();

            /*
             * @brief resets the motion error.
             */
            void resetMotionError();
#endif

            /**
             * @brief Checks if the motor is still in motion.
             *
             * The following property will indicate the motion
             *
             * - VAR.MOVING
             */
            bool isMoving();

            /*
             * @brief This method returns if the home search was done and
             *        indicates if the MoCon position is synchronous with the
             *        hardware.
             */
            bool isAtHome();

            /**
             * @brief Checks if the motor has finished the motion.
             *
             * The following property will indicate the motion completeness
             *
             * - VAR.MOTION_COMPLETE
             *
             * @todo this method doesn't update this property active. It just
             *       readout its property. An active readout of the motion
             *       complete event should be implemented.
             */
            bool isMotionComplete();

            /**
             * @brief Set the MOTOR_COMPLETE flag.
             *
             * The following property is used
             *
             * - VAR.MOTION_COMPLETE
             */
            void setMotionComplete(bool _complete);

            /**
             * @brief Checks if the motor is in limit.
             *
             * This method checks the motor controller limit switches and set
             * the corresponding properties.
             * If the motor is not in the hardware limit, this method checks if
             * the current position (stored in the VAR.POSITION property) is in
             * the valid range.
             * If the current position out of the valid range, the limit properties
             * indicate that the motor is in the software limits.
             *
             * The status will be stored in the properties:
             *
             * - VAR.LIMIT
             *
             * @throw ::Basda::MoCon::LimitSwitchException
             * @throw ::Basda::MoCon::MotorNotInitializedException
             *
             * @see IN_VALID_RANGE, SOFTWARE_LIMIT, HARDWARE_LIMIT
             */
            int isAtLimit();

            /**
             * @brief This method returns the current activity status.
             *
             * It returns the 16 bit activity register:
             * - bit  0: phasing initialized
             * - bit  1: at maximal velocity
             * - bit  2: tracking
             * - bit  3: current profile mode
             * - bit  4: -
             * - bit  5: -
             * - bit  6: -
             * - bit  7: axis settled
             * - bit  8: motor on/off
             * - bit  9: position capture
             * - bit 10: in motion
             * - bit 11: in positive limit
             * - bit 12: in negative limit
             * - bit 13: limit profile segment
             * - bit 14: -
             * - bit 15: -
             *
             * @return a 16 bit value
             */
            unsigned int getActivityStatus();

            /**
             * @brief This method returns the current signal status.
             *
             * It returns the 16 bit signal register:
             * - bit  0: encoder A
             * - bit  1: encoder B
             * - bit  2: encoder index
             * - bit  3: home switch
             * - bit  4: positive limit
             * - bit  5: negative limit
             * - bit  6: axis In
             * - bit  7: hall A
             * - bit  8: hall B
             * - bit  9: hall C
             * - bit 10: axis out
             * - bit 11: -
             * - bit 12: -
             * - bit 13: -
             * - bit 14: -
             * - bit 15: -
             *
             * @return a 16 bit value
             */
            unsigned int getSignalStatus();

            /**
             * @brief This method returns the current absolute position.
             *
             * The current position will be stored in the property
             *
             * - VAR.POSITION
             *
             * The motor controller position will be converted based on the unit
             * stored in the VAR.UNIT property.
             *
             * @return the absolute position in steps/counts
             */
            int getMEncPosition();

            /**
             * @brief This method returns the current position of the absolute encoder.
             *
             * @return the absolute encoder position in steps/counts
             */
            int getAEncPosition();

            /**
             * @brief This method returns the current position of the incremental encoder.
             *
             * @return the incremental encoder position in steps/counts
             *
             * @throw ::Basda::MoCon::IEncNotInitializedException
             */
            int getIEncPosition();

            /**
             * @brief This method returns the current velocity.
             *
             * The current velocity will be stored in the property
             *
             * - VAR.VELOCITY
             *
             * @return the current velocity in rev/min
             */
            int getVelocity();

            /**
             * @brief This method returns the current velocity of the incremental encoder.
             *
             * @return the current velocity of the incremental encoder
             *
             * @throw ::Basda::MoCon::IEncNotInitializedException
             */
            int getIEncVelocity();

            /**
             * @brief This method returns the distance between the start point
             *        and the reference point.
             *
             * The software position counter of the motor controller is zero
             * after the motor controller is switched on. The moveToHome() method
             * have to be called first in order to align the software position
             * counter with the hardware position counter of the motor controller.
             *
             * @return the start point - reference point distance
             */
            int getStartHomeDistance();

            /**
             * @brief This method read the motor settings from the EEPROM.
             *
             * @throw ::Basda::MoCon::MotorSettingsAccessException
             * @throw ::Basda::MoCon::MotorInMotionException
             * @throw ::Basda::MoCon::ParamMissingException
             * @throw ::Basda::MoCon::NoAmpplifierException
             * @throw ::Basda::MoCon::MicrostepResolutionException
             */
            void loadMotorSettings();

            /**
             * @brief This method save the motor settings in the EEPROM.
             *
             * @throw ::Basda::MoCon::MotorSettingsAccessException
             * @throw ::Basda::MoCon::MotorInMotionException
             * @throw ::Basda::MoCon::ParamMissingException
             * @throw ::Basda::MoCon::NoAmpplifierException
             * @throw ::Basda::MoCon::MicrostepResolutionException
             */
            void saveMotorSettings();

            /**
             * @brief This method wait till an event was received
             *
             * The timeout parameter is defined in the property
             * CFG.CONNECTION.EVENT_TIMEOUT and defines how long the method
             * should wait for an incoming event.
             */
            void waitForEvent();

            /**
             * @brief This method synchronize the MoCon time with the PC time.
             *
             * This method ask the MoCon for the current MoCon cycle and stores
             * the PC time and the MoCon cycle it in the properties:
             *
             * - VAR.TIME.REFERENCE.MOCON
             * - VAR.TIME.REFERENCE.SERVER
             * - VAR.TIME.CURRENT.MOCON
             * - VAR.TIME.CURRENT.SERVER
             *
             * The VAR.TIME.REFERENCE properties keep the reference time, which
             *                        will be updated only when this method is called.
             * The VAR.TIME.CURRENT.MOCON properties keep the current time and
             *                            will be updated every time when the
             *                            synchroniseTime() or getCurrentTime()
             *                            method is called.
             *
             * @see getCurrentTime()
             */
            Nice::I64 getReferenceTime();

            /**
             * @brief This method stores the current PC time and Mocon cycles in
             *        the properties.
             *
             * This method ask the MoCon for the current MoCon cycle and stores
             * the PC time and the MoCon cycle it in the properties:
             *
             * - VAR.TIME.CURRENT.MOCON
             * - VAR.TIME.CURRENT.SERVER
             *
             * These properties keep the current time and will be updated every
             * time when the synchroniseTime() or getCurrentTime() method is called.
             *
             * @see getReferenceTime()
             */
            Nice::I64 getCurrentTime();

#if 0
            /**
            * @brief This method set the sample rate for the time based trace
            *
            * @param _sampleRate defines every which motor controller clock cycle a value has to be logged. (1..65000)
            */
             void setTimeBasedTraceSampleRate(const unsigned int _sampleRate);

            /**
            * @brief Defines the trace type.
            *
            * The MoCon card can control up to 8 motors driven by 2 chipsets.
            * The first chipset controls the motors 1-4, the second the motors 5-8. For each
            * chipset are 4 memory cells, available which can be programmed. With this method can be defined,
            * which memory cell (buffer) should collect which data type.
            *
            * @note The MoCon card provides only 2x4 memory cells for 8 motors in total. That means
            * that a single motor can trace up to 4 different data types. But 2 motors (driven by the same chipset)
            * can trace only 2 different data types at the same time. In case all motors are selected for a trace than is only one memory cell available for each motor.
            *
            * The data type can be:
            * -  0: None
            * -  1: Commanded Position
            * -  2: Commanded Velocity
            * -  3: Commanded Acceleration
            * -  4: Actual Position
            * -  5: Actual Velocity
            * -  6: Position Error
            * -  7: PID Error
            * -  8: Event Status Register
            * -  9: Activity Status Register
            * - 10: Signal Status Register
            * - 11: Integral
            * - 12: Derivative
            * - 13: Motor Command
            * - 14: Capture Register
            * - 15: Chipset Time (cycles)
            *
            * @param _buffer The buffer to store the trace data (1..8)
            * @param _type   Which data type should be traced (0..15)
            *
            * @throw ::Basda::MoCon::InitTraceSetException
            *
            * @see MPIA/MoCon/CommandIDs.h - ValueTraceType
            */
             void setTimeBasedTraceType(const unsigned int _buffer, const ValueTraceType _type);

            /**
            * @brief This method returns the collected trace data.
           *
            * This method will send a request to the MoCon to return the collected data. It is possible to define how many data the MoCon should be return (_numberOfSamples). With the parameter "_numberOfLines" is it possible to read a certain number of lines in order to update the completion bar. To read the next trace data block please use the "receiveTraceData" method in order to avoid a multiple request to the MoCon.
            *
            * @note Please don't send a new request to the MoCon during the trace data transfer. Wait until the command acknowledge is received! The MoCon will hang up otherwise (Fatal error: incorrect memory access).
            *
            * The incoming trace data will be parsed using the parseTraceData() method.
            *
            * @param _numberOfSamples its optional, it defines how many trace data the MoCon should send at once. Is nothing is defined all collected data will be send
            * @param _numberOfLines its optional, it defines how many lines have to be read. Is nothing is defined all collected data will be read at once.
            *
            * @see ::Basda::MoConModuleEvent::parseTraceData
            */
             void getTimeBasedTraceData(const unsigned int _numberOfSamples = -1, const int _numberOfLines = -1);

            /**
            * @brief This method reads the received trace data.
            *
            * This method reads the already transmitted traced data from the Ethernet. It doesn't send a request to the MoCon. With the parameter "_numberOfLines" is it possible to read a certain number of lines in order to update the completion bar.
            *
            * The incoming trace data will be parsed using the parseTraceData() method.
            *
            * @param _numberOfLines its optional, it defines how many lines have to be read. Is nothing is defined all collected data will be read at once.
            *
            * @see ::Basda::MoConModuleEvent::parseTraceData
            */
             void receiveTimeBasedTraceData(const unsigned int _numberOfLines = -1);

            /**
            * @brief Defines the trace type.
            *
            * The MoCon card can control up to 8 motors driven by 2 chipsets. The first chipset controls the motors 1-4, the second the motors 5-8. For each chipset are 4 memory cells available which can be programmed. With this method can be defined which memory cell (buffer) should collect which data type.
            *
            * @note The MoCon card provides only 2x4 memory cells for 8 motors in total. That means that a single motor can trace up to 4 different data types. But 2 motors (driven by the same chipset) can trace only 2 different data types at the same time. In case all motors are selected for a trace than is only one memory cell available for each motor.
            *
            * The data type can be:
            * -  0: None
            * -  1: Commanded Position
            * -  2: Commanded Velocity
            * -  3: Commanded Acceleration
            * -  4: Actual Position
            * -  5: Actual Velocity
            * -  6: Position Error
            * -  7: PID Error
            * -  8: Event Status Register
            * -  9: Activity Status Register
            * - 10: Signal Status Register
            * - 11: Integral
            * - 12: Derivative
            * - 13: Motor Command
            * - 14: Capture Register
            * - 15: Chipset Time (cycles)
            *
            * @param _buffer The buffer to store the trace data (1..8)
            * @param _type   Which data type should be traced (0..15)
            * @param _timeBase its optional, (1..65000, 1=default)
            *
            * @throw ::Basda::MoCon::InitTraceSetException
            *
            * @see MPIA/MoCon/CommandIDs.h - ValueTraceType
            */
             void setEventBasedTraceType(const unsigned int _buffer, const ValueTraceType _type, const unsigned int _timeBase = 1);
#endif /* 0 */

            /**
             * @brief This method set the external buffer size.
             *
             * @param _bufferSize the buffer size 1..4294967295
             * @param _extended enables the extended mode that allows to program
             *                  the external profile with
             *                  < index >, < time >, < velocity >, < position >,
             *                  < acceleration >, < jerk >,
             *                  otherwise the external profile needs only the parameter
             *                  < index >, < time >, < velocity >, < position >
             *                  (disable = 0, enable = 1)
             *
             * @see ::Basda::MoConModuleEvent::parseTraceData
             */
            void setExternalProfileBufferSize(const unsigned int _bufferSize,
                                              bool _extended = true);

#if 0
            /**
             * @brief This method returns the size of the external profile.
             **/
            unsigned int getExternalProfileSize();
#endif

            /**
             * @brief This method set the external profile data.
             *
             * @param _index the data value index 0..4294967295
             * @param _timeBase 0..4294967295
             * @param _velocity -2147483647..2147483647
             * @param _position -2147483647..2147483647
             * @param _acceleration optional, has to be defined if the extended mode is enabled
             * @param _jerk optional, has to be defined if the extended mode is enabled
             *
             * @see ::Basda::MoConModuleEvent::parseTraceData
             */
            void setExternalProfileData(const unsigned int _index,
                                        const unsigned int _timeBase,
                                        const int _velocity,
                                        const int _position,
                                        const int _acceleration = 0,
                                        const int _jerk = 0);

            /**
             * @brief This method starts the external profile from the beginning
             *        or from the last position.
             *
             * @param _startMode - define whether the profile should start from
             *                     the beginning or from the current position
             * @param _starTime  - the start time in cycle clocks (-1 is chosen
             *                     to start the profile immediately;
             *                     start time 0 (zero means to start at cycle zero))
             *
             * @see MPIA/MoCon/CommandIDs.h - ValueStartMode
             **/
            void setExternalProfileStart(const ValueStartMode::Constant _startMode,
                                         const Nice::Date _startTime =
                                                 Nice::Date::microSeconds(-1));

#if 0
            /**
             * @brief This method starts the external profile at a defined time.
             *
             * @param _startTime - the start time in cycle
             * @param _startMode - define whether the profile should start from
             *                     the beginning or from the current position
             *
             * @see MPIA/MoCon/CommandIDs.h - ValueStartMode
             */
             void setExternalProfileTimeStart(const unsigned int _startTime, const ValueStartMode _startMode);
#endif

            /**
             * @brief This method stops the external profile.
             */
            void setExternalProfileStop();

            /**
             * @brief This method returns the actual index of the external profile.
             */
            int getExternalProfileInfo();

#if 0
            /*
             * @brief initialized external profile
             *
             * @param _segmentLength     - the time resolution in seconds
             * @param _maxSamplesPerSegment - how many values are maximal
             *                                collected in one segment
             * @param _minSamplesPerSegment - how many values are minimal
             *                                collected in one segment
             * @param _faultTolerance    - the maximal position error that can happen
             */
            Nice::Time initExternalProfile(Nice::Time _segmentLength,
                                     unsigned int _maxSamplesPerSegment,
                                     unsigned int _minSamplesPerSegment,
                                     unsigned int _faultTolerance);
#endif

            /*
             * @brief initialized external profile
             *
             * @param _frequency            - the sampling frequency
             * @param _maxSamplesPerSegment - how many values are maximal
             *                                collected in one segment
             * @param _minSamplesPerSegment - how many values are minimal
             *                                collected in one segment
             * @param _faultTolerance    - the maximal position error that can happen
             */
            Nice::Time initExternalProfile(int _frequency,
                                     unsigned int _maxSamplesPerSegment,
                                     unsigned int _minSamplesPerSegment,
                                     unsigned int _faultTolerance);

            /**
             * @brief This method freed the allocated memory of the external profile.
             */
            void clearExternalProfileBuffer();

            /**
             * @brief This method calculates the transition from one trajectory
             * to another if a trajectory already exist.
             *
             * @param _date - the external profile start date
             * @param _positionSequence  - supporting points of the spline in steps
             * @param _transitionLength - the time how long the transition should take
             *
             */
            void calculateTransition(const Nice::Date &_date,
                                     const Nice::NPoint &_positionSequence);
            void calculateTransition(const Nice::Date &_date,
                                     const Nice::NPoint &_positionSequence,
                                     const Nice::Time &_transitionLength);

            /**
             * @brief This method convert the given trajectory to a motor controller profile.
             *
             * The external profile can be setup with a spline which has some
             * supporting points (in PC time and steps). This spline will be
             * converted to motor controller time and microsteps steps.
             *
             * @return the number of generated segments
             *
             * The final external profile coordinates will be calculated as followed:
             *
             * \f$ point.xp = (double) lrint(i * m_timeResolution.toMicroSecondsDouble() / m_cycleTime) \f$
             *
             * \f$ point.yp = _positionSequence.at(i) * m_microsteps; \f$
             *
             * where i  is the index of the position sequence
             *       the other variables are self-explained, i hope :)
             **/
            unsigned int fitTrajectory();
            unsigned int shinsFitTrajectory(); // modified version for SHARK
            int shinsGetStartingRamp(const Nice::NPoint & _positionSequence, double time_interval_microseconds);
            Nice::Date shinsGetEffectiveProfileStartDate(){ if(!m_externalProfileBuffer.empty()){ return m_externalProfileBuffer.at(0).startDate;} else { return Nice::Date();}}
            int sharkDerotatorBacklashProcedure(int procedure);


            /*
             * @brief This method validates the external profile. It simulates
             *        the MoCon external profile calculation and compares the
             *        results for every step with the maximal velocity, acceleration
             *        and jerk. The position values for every step is checked
             *        against the travelrange too.
             */
            void validateExternalProfile();

            /*
             * @brief This method buffers the external profile.
             */
            unsigned int bufferExternalProfile();

            /**
             * @brief This uploads the external profile data.
             **/
            Nice::Date uploadExternalProfile();
            Nice::Date shinsUploadExternalProfile();

            void uploadExternalProfile(const Nice::SeqSeqInt &_segments);

            bool isExternalProfileDone();
            unsigned int ExternalProfileCompletion();

            /**
             * @brief Change the absolute position of the motors.
             *
             * The motor will not move, but the current absolute position will be
             * set to the given position value.
             * The new position value can only be inside the travel range.
             *
             * @param _position the new absolute position in steps
             *
             * @throw ::Basda::MoCon::OutOfRangeException
             */
            void setProfilePosition(double _position);

            /**
             * @brief This method enables the flag to indicate whether the CoCon detected
             *        a collision. In that case the limit switch exception 'broken cable'
             *        will be ignored.
             *
             * @param _collision if true a collision was detected by the CoCon
             */
            void setCollision(bool _collisionNegative, bool _collisionPositive);

        private:
            /**
             * @brief This is the implementation of the handler for the incoming
             *        events and function errors.
             *
             * @note Trace methods are not up to date and commented.
             *
             * @author Frank Kittmann
             * @version 09.06.24
             * @date 2009.06.24
             */
            struct MoConModuleEvent : HandlerImpl
            {
                    //         std::ofstream *m_fout;
                    /**
                     * @brief Constructor
                     *
                     * @param _config the root of the configuration tree
                     */
                    MoConModuleEvent(Nice::JointPtr _config)
                            : HandlerImpl(_config)
                    {
                        //             m_index.resize((unsigned int)Basda::ValueTraceTypeMax, 0);
                        //             m_sampleRate = 1;
                        //             m_fout = new std::ofstream( "/home/kittmann/workspace/TwiceAsNice/unstable/basda/src/Service/Mocca/etc/test", std::ios_base::app );
                    }
                    ;

                    /**
                     * @brief implementation of the event handler
                     *
                     * The incoming event will be sorted to the following properties:
                     * - VAR.MOTION_COMPLETE
                     * - VAR.ON_POSITIVE_LIMIT
                     * - VAR.ON_NEGATIVE_LIMIT
                     * - VAR.MOTION.ERROR
                     *
                     * The event trace messages will be parsed using the
                     * parseTraceData() method
                     *
                     * @param _event the event message
                     *
                     * @throw ::Basda::MoCon::MotionErrorException
                     *
                     * @see parseTraceData
                     */
                    void eventHandler(const std::string &_event)
                    {
                        std::stringstream event(_event);
                        std::stringstream indexEvent;
                        std::string errorMsg;
                        unsigned int eventNo;
                        //             unsigned int type;
                        //             double value;

                        event >> eventNo;

                        switch (eventNo)
                        {
                            case Basda::Event::EVENT__MSG_MOTION_COMPLETE:
                                D_LOG("Motion complete. " << m_config->node(Basda::Mocca::MoCon::varMotionComplete())->path() << ": 1");
                                setMotionComplete();
                                break;
                            case Basda::Event::EVENT__MSG_IN_POS_LIMIT:
                                errorMsg = "Motor is in positive limit.";
                                I_LOG(errorMsg)
                                D_LOG(errorMsg << " " << m_config->node(Basda::Mocca::Dev::PropertyName::limit())->path() << ": " << Basda::Limit::HARDWARE_LIMIT);
                                m_config->setAtNode<int>(
                                        Basda::Mocca::Dev::PropertyName::limit(),
                                        Basda::Limit::HARDWARE_LIMIT);
                                setMotionComplete();
                                break;
                            case Basda::Event::EVENT__MSG_IN_NEG_LIMIT:
                                errorMsg = "Motor is in negative limit.";
                                I_LOG(errorMsg)
                                D_LOG(errorMsg << " " << m_config->node(Basda::Mocca::Dev::PropertyName::limit())->path() << ": " << -Basda::Limit::HARDWARE_LIMIT);
                                m_config->setAtNode<int>(
                                        Basda::Mocca::Dev::PropertyName::limit(),
                                        -Basda::Limit::HARDWARE_LIMIT);
                                setMotionComplete();
                                break;
                            case Basda::Event::EVENT__MSG_MOTION_ERROR:
                                errorMsg = "Motion error. Motor has lost too many steps while in motion and will turn off.";
                                E_LOG(errorMsg)
//                                m_config->setAtNode<bool>( Basda::Mocca::Dev::PropertyName::motionError(), true);
                                setMotionComplete();
                                E_THROW(::Basda::MoCon::MotionErrorException, errorMsg);
                                break;
                            case Basda::Event::EVENT__MSG_EVENT_TRACE_DATA:
                                D_LOG("Trace data: " << event.str())
                                //                         event >> type >> value;
                                //                         indexEvent << m_index.at(type) << " " << type << " " << value;
                                //                         parseTraceData(indexEvent);
                                //                         m_index.at(type)++;
                                break;
                            case Basda::Event::EVENT__MSG_EVENT_INVALID_INSTRUCTION:
//                                errorMsg = "Event message invalid instruction. Please report to mohr@mpia.de.";
                                errorMsg = "MoCon reported an invalid instruction. Do a hardware reset of the MoCon or "
                                           "a software reset via the command '1 8 0'. Services might "
                                           "reconnect automatically.";
                                E_LOG(errorMsg)
//                                m_config->setAtNode<bool>( Basda::Mocca::Dev::PropertyName::motionError(), true);
                                setMotionComplete();
                                E_THROW(::Basda::MoCon::MotionErrorException, errorMsg);
                                break;
                        }
                    }

                    /**
                     * @brief implementation of the function error handler
                     *
                     * It logs the function error and throws the corresponding error.
                     *
                     * @param _errorNo the error number
                     *
                     * @throw ::Basda::MoCon::CheckSumException
                     * @throw ::Basda::MoCon::CmdForStepperException
                     * @throw ::Basda::MoCon::CmdForServoException
                     * @throw ::Basda::MoCon::RevolutionNotDefinedException
                     * @throw ::Basda::MoCon::MotorInMotionException
                     * @throw ::Basda::MoCon::ParamMissingException
                     * @throw ::Basda::MoCon::AADException
                     * @throw ::Basda::MoCon::NoAmpplifierException
                     * @throw ::Basda::MoCon::AmpIncompatibleException
                     * @throw ::Basda::MoCon::MicrostepResolutionException
                     * @throw ::Basda::MoCon::MotorNotInitializedException
                     * @throw ::Basda::MoCon::MotorInPosLimitException
                     * @throw ::Basda::MoCon::MotorInNegLimitException
                     * @throw ::Basda::MoCon::MotorSettingsIncompleteException
                     * @throw ::Basda::MoCon::MotorSettingsAccessException
                     * @throw ::Basda::MoCon::IEncNotInitializedException
                     * @throw ::Basda::MoCon::InitTraceSetException
                     * @throw ::Basda::MoCon::NotEnoughMemoryException
                     * @throw ::Basda::MoCon::ExternalRAMException
                     * @throw ::Basda::MoCon::BufferOverrunException
                     * @throw ::Basda::MoCon::NoTraceBufferDefinedException
                     * @throw ::Basda::MoCon::BufferAlreadyReservedException
                     * @throw ::Basda::MoCon::NoBufferDefinedException
                     * @throw ::Basda::MoCon::BothLimitsActiveException
                     * @throw ::Basda::MPIA::FunctionError
                     */
                    void functionErrorHandler(const std::string _errorNo)
                    {
                        std::stringstream error(_errorNo);
                        unsigned int errorNo;

                        error >> errorNo;
                        std::string errorMsg;

                        switch (errorNo)
                        {
                            case Basda::Error::ERR__COM_WITH_MC:
                                errorMsg = "Checksum error.";
                                E_THROW(::Basda::MoCon::CheckSumException, errorMsg);
                                break;
                            case Basda::Error::ERR__CMD_FOR_2500:
                                errorMsg =
                                        "The method is only for stepper chipset.";
                                E_THROW(::Basda::MoCon::CmdForStepperException, errorMsg);
                                break;
                            case Basda::Error::ERR__CMD_FOR_2800:
                                errorMsg =
                                        "The method is only for servo chipset.";
                                E_THROW(::Basda::MoCon::CmdForServoException, errorMsg);
                                break;
                            case Basda::Error::ERR__REV_NOT_DEF:
                                errorMsg =
                                        "The steps/count per revolution have to be defined first.";
                                E_THROW(::Basda::MoCon::RevolutionNotDefinedException, errorMsg);
                                break;
                            case Basda::Error::ERR__MOT_IN_MOTION:
                                errorMsg = "Motor is still in motion.";
                                E_THROW(::Basda::MoCon::MotorInMotionException, errorMsg);
                                break;
                            case Basda::Error::ERR__INIT_BASIS_SET:
                                errorMsg =
                                        "Some parameter are missing to initialize basic motor settings.";
                                E_THROW(::Basda::MoCon::ParamMissingException, errorMsg);
                                break;
                            case Basda::Error::ERR__INIT_AAD:
                                errorMsg =
                                        "A communication error with the EEPROM at the amplifier card occur.";
                                E_THROW(::Basda::MoCon::AADException, errorMsg);
                                break;
                            case Basda::Error::ERR__AMP_NA:
                                errorMsg = "No amplifier detected.";
                                E_THROW(::Basda::MoCon::NoAmpplifierException, errorMsg);
                                break;
                            case Basda::Error::ERR__AMP_MC_NC:
                                errorMsg =
                                        "Detected amplifier is not compatible with the motor chipset.";
                                E_THROW(::Basda::MoCon::AmpIncompatibleException, errorMsg);
                                break;
                            case Basda::Error::ERR__MICROSTEP_NA:
                                errorMsg =
                                        "Amplifier does not support the the current microstep resolution.";
                                E_THROW(::Basda::MoCon::MicrostepResolutionException, errorMsg);
                                break;
                            case Basda::Error::ERR__MOTOR_NOT_INIT:
                                errorMsg = "Motor is not initialized.";
                                E_THROW(::Basda::MoCon::MotorNotInitializedException, errorMsg);
                                break;
                            case Basda::Error::ERR__MOTOR_IN_POS_L:
                                m_config->setAtNode<int>(
                                        Basda::Mocca::Dev::PropertyName::limit(),
                                        Basda::Limit::HARDWARE_LIMIT);
                                setMotionComplete();
                                errorMsg = "Motor is in positive limit.";
                                E_THROW(::Basda::MoCon::MotorInPosLimitException, errorMsg);
                                break;
                            case Basda::Error::ERR__MOTOR_IN_NEG_L:
                                m_config->setAtNode<int>(
                                        Basda::Mocca::Dev::PropertyName::limit(),
                                        Basda::Limit::HARDWARE_LIMIT);
                                setMotionComplete();
                                errorMsg = "Motor is in negative limit.";
                                E_THROW(::Basda::MoCon::MotorInNegLimitException, errorMsg);
                                break;
                            case Basda::Error::ERR__FIND_HOME_NA:
                                errorMsg =
                                        "Motor settings incomplete. Home search is not available.";
                                E_THROW(::Basda::MoCon::MotorSettingsIncompleteException, errorMsg);
                                break;
                            case Basda::Error::ERR__NO_ACCESS_MS:
                                errorMsg =
                                        "No access to the motor settings at the EEPROM.";
                                E_THROW(::Basda::MoCon::MotorSettingsAccessException, errorMsg);
                                break;
                            case Basda::Error::ERR__IENC_NOT_INIT:
                                errorMsg =
                                        "No incremental encoder initialized.";
                                E_THROW(::Basda::MoCon::IEncNotInitializedException, errorMsg);
                                break;
                            case Basda::Error::ERR__INIT_TRACE_SET:
                                errorMsg =
                                        "The trace settings is not complete. Some parameter are still missing.";
                                E_THROW(::Basda::MoCon::InitTraceSetException, errorMsg);
                                break;
                            case Basda::Error::ERR__TRACE_TO_SMALL:
                                errorMsg =
                                        "Not enough memory for the given number of samples.";
                                E_THROW(::Basda::MoCon::NotEnoughMemoryException, errorMsg);
                                break;
                            case Basda::Error::ERR__EXTERN_RAM:
                                errorMsg = "External buffer overflow.";
                                E_THROW(::Basda::MoCon::ExternalRAMException, errorMsg);
                                break;
                            case Basda::Error::ERR__TRACE_BUFFER_OR:
                                errorMsg =
                                        "Buffer overrun. Data couldn't send fast enough.";
                                E_THROW(::Basda::MoCon::BufferOverrunException, errorMsg);
                                break;
                            case Basda::Error::ERR__TRACE_BUF_NDEF:
                                errorMsg = "Trace buffer is not allocated.";
                                E_THROW(::Basda::MoCon::NoTraceBufferDefinedException, errorMsg);
                                break;
                            case Basda::Error::ERR__EP_SIZE_SET:
                                errorMsg = "Buffer already reserved.";
                                E_THROW(::Basda::MoCon::BufferAlreadyReservedException, errorMsg);
                                break;
                            case Basda::Error::ERR__EP_SIZE_NOT_SET:
                                errorMsg =
                                        "The buffer size is not defined yet.";
                                E_THROW(::Basda::MoCon::NoBufferDefinedException, errorMsg);
                                break;
                            case Basda::Error::ERR__INIT_LIMIT_ERR:
                                errorMsg = "Both limits are active.";
                                E_THROW(::Basda::MoCon::BothLimitsActiveException, errorMsg);
                                break;
                        }
                    }
                    ;

                    void setMotionComplete()
                    {
                        m_config->setAtNode<bool>(Basda::Mocca::MoCon::varMotionComplete(), true);
                    }

#if 0
                    /**
                    * @brief This method sets the sample rate to calculate the timestamp of the incoming trace data.
                    *
                    * @param _sampleRate the trace sample rate
                    *
                    * @see parseTraceData
                    */
                    void setTraceSampleRate(unsigned int _sampleRate) { m_sampleRate = _sampleRate; };

                    /**
                    * @brief This method save the start time of the trace.
                    *
                    * The trace start time is the current system time and allows to show all traces in one plot in order to have a chronological sequence of all measurements.
                    * Is an overlay of all plots is desired the corresponding start time has to be subtracted from a each time stamps.
                    *
                    * @see parseTraceData
                    */
                    void setTimeStampNow()
                    {
                        m_traceStart = Nice::Date::now();
                        for (unsigned int i = 0; i < m_index.size(); i++)
                        m_index.at(i) = 0;
                    };

                    /**
                    * @brief This method sort the incoming trace data to its property and calculate the corresponding time stamp.
                    *
                    * A trace data set consist of an index, a sample type and the value itself. The index is just a counter that counts the traced values starting from zero (0). The sample type is the type ID of the traced data. The type ID is defined in the MoCon/CommandIDs.h (ValueTraceType).
                    *
                    * This procedure extract all parameter of a data set and store the value with its time stamp directly in the corresponding property. The artificial calculated time stamp represents the run of the curve, since no motor controller time stamps exist. The time stamp calculation is done with the following equation:
                    *
                    * \f$ timeStamp = m_traceStart + index * cycleTime * m_sampleRate \f$
                    *
                    * where timeStamp    represent the time stamp of the current value,
                    *       m_traceStart is the tracing start time,
                    *       index        is the counter of the current value,
                    *       cycleTime    is the clock cycle time of the motor controller chipset,
                    *       m_sampleRate is the trace sample rate
                    *
                    * The received data will be sorted in the following properties:
                    * - VAR.TRACE.DATA.COMMANDED_POSITION
                    * - VAR.TRACE.DATA.COMMANDED_VELOCITY
                    * - VAR.TRACE.DATA.COMMANDED_ACCELERATION
                    * - VAR.TRACE.DATA.ACTUAL_POSITION
                    * - VAR.TRACE.DATA.ACTUAL_VELOCITY
                    * - VAR.TRACE.DATA.POSITION_ERROR
                    * - VAR.TRACE.DATA.PID_ERROR
                    * - VAR.TRACE.DATA.EVENT_STATUS_REGISTER
                    * - VAR.TRACE.DATA.ACTIVITY_STATUS_REGISTER
                    * - VAR.TRACE.DATA.SIGNAL_STATUS_REGISTER
                    * - VAR.TRACE.DATA.INTEGRAL
                    * - VAR.TRACE.DATA.DERIVATIVE
                    * - VAR.TRACE.DATA.MOTOR_COMMAND
                    * - VAR.TRACE.DATA.CAPTURE_REGISTER
                    * - VAR.TRACE.DATA.CHIPSET_TIME
                    *
                    * @param _ret the incomming trace data.
                    */
                    void parseTraceData(std::stringstream &_ret)
                    {
                         unsigned int index;
                         unsigned int type;
                         double value;
                         double cycleTime = m_config->getAtNode<double>( "CFG.DATASHEET.TIME_PER_CYCLE");
                    
                         Nice::PropertyPtr commandedPosition= m_config->node("VAR.TRACE.DATA.COMMANDED_POSITION")->leaf();
                         Nice::PropertyPtr commandedVelocity= m_config->node("VAR.TRACE.DATA.COMMANDED_VELOCITY")->leaf();
                         Nice::PropertyPtr commandedAcceleration= m_config->node("VAR.TRACE.DATA.COMMANDED_ACCELERATION")->leaf();
                         Nice::PropertyPtr actualPosition= m_config->node("VAR.TRACE.DATA.ACTUAL_POSITION")->leaf();
                         Nice::PropertyPtr actualVelocity= m_config->node("VAR.TRACE.DATA.ACTUAL_VELOCITY")->leaf();
                         Nice::PropertyPtr positionError= m_config->node("VAR.TRACE.DATA.POSITION_ERROR")->leaf();
                         Nice::PropertyPtr pidError= m_config->node("VAR.TRACE.DATA.PID_ERROR")->leaf();
                         Nice::PropertyPtr eventStatusRegister= m_config->node("VAR.TRACE.DATA.EVENT_STATUS_REGISTER")->leaf();
                         Nice::PropertyPtr activityStatusRegister= m_config->node("VAR.TRACE.DATA.ACTIVITY_STATUS_REGISTER")->leaf();
                         Nice::PropertyPtr signalStatusRegister= m_config->node("VAR.TRACE.DATA.SIGNAL_STATUS_REGISTER")->leaf();
                         Nice::PropertyPtr integral= m_config->node("VAR.TRACE.DATA.INTEGRAL")->leaf();
                         Nice::PropertyPtr derivative= m_config->node("VAR.TRACE.DATA.DERIVATIVE")->leaf();
                         Nice::PropertyPtr motorCommand= m_config->node("VAR.TRACE.DATA.MOTOR_COMMAND")->leaf();
                         Nice::PropertyPtr captureRegister= m_config->node("VAR.TRACE.DATA.CAPTURE_REGISTER")->leaf();
                         Nice::PropertyPtr chipsetTime= m_config->node("VAR.TRACE.DATA.CHIPSET_TIME")->leaf();
                   
                         std::string traceData;
                         Nice::Date timeStamp;
                  
                         while(_ret >> index)
                         {
                             std::getline(_ret, traceData);
                 
                             std::stringstream strTraceData(traceData);
                             while(strTraceData >> type >> value)
                             {
                                 timeStamp = m_traceStart + Nice::Time::seconds( (double)index * cycleTime * (double)m_sampleRate);
                    //                     *m_fout << index << "\t" << timeStamp << std::endl;
                                 switch (type)
                                 {
                                     case MOCON_TYPE_COMMANDED_POSITION:
                                         commandedPosition->set<double>(value, timeStamp);// * 8
                                         break;
                                     case MOCON_TYPE_COMMANDED_VELOCITY:
                                         commandedVelocity->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_COMMANDED_ACCELERATION:
                                         commandedAcceleration->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_ACTUAL_POSITION:
                                         actualPosition->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_ACTUAL_VELOCITY:
                                         actualVelocity->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_POSITION_ERROR:
                                         positionError->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_PID_ERROR:
                                         pidError->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_EVENT_STATUS_REGISTER:
                                         eventStatusRegister->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_ACTIVITY_STATUS_REGISTER:
                                         activityStatusRegister->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_SIGNAL_STATUS_REGISTER:
                                         signalStatusRegister->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_INTEGRAL:
                                         integral->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_DERIVATIVE:
                                         derivative->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_MOTOR_COMMAND:
                                         motorCommand->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_CAPTURE_REGISTER:
                                         captureRegister->set<double>(value, timeStamp);
                                         break;
                                     case MOCON_TYPE_CHIPSET_TIME:
                                         chipsetTime->set<double>(value, timeStamp);
                                         break;
                                 }
                             }
                         };
                     };

                    /**
                    * @brief member for the sample rate to calculate the time stamp
                    */
                    unsigned int m_sampleRate;

                    /**
                    * @brief member for trace starting time
                    */
                    Nice::Date m_traceStart;

                    /**
                    * @brief member for the trace data index
                    *
                    * The incoming event trace data doesn't contain an index. This member will be increased every time when a logged data arrives.
                    */
                    std::vector<unsigned int> m_index;
#endif /* 0 */
            };

            typedef IceUtil::Handle<MoConModuleEvent> MoConModuleEventPtr;

            /**
             * @brief This method add some internal properties like status properties.
             */
            void addInternalProperties();

            void checkTravelRange();

            void travelRangeChanged(const Nice::Point &_a);

            /**
             * @brief member for the extended external profile mode
             */
            bool m_extendedProfileParamter;

            unsigned int m_bufferSize;

            unsigned int m_externalProfileIndexCycle;

            Nice::Time m_timeResolution;
            int m_frequency;

            /**
             * @brief member for the extended external profile mode
             */
            Basda::MoConModuleProfile m_profile;

            /*
             * @brief position point cloud which the MoCon external profile has to follow
             */
            Nice::NPoint m_positionSequence;
            Nice::NPoint m_positionSequenceBackup;
            Nice::Date m_startDate;

            Nice::Point m_travelRange;

            Nice::Time m_blockSize;

            int m_currentPosition;

            Nice::Date m_currentPcDate;
            Nice::I64 m_currentMoConClocks;

            double m_cycleTime;

            unsigned int m_microsteps;

            bool m_collisionPositive;
            bool m_collisionNegative;

            Nice::U16 m_basicResolution;

            Nice::U32 m_basicAcceleration;

            /**
             * The basic acceleration is set during the external profile initialization,
             * to keep the acceleration constant over the whole trajectory.
             */
            double m_accelerationPerCycle;

            std::vector<Basda::MoConModuleProfile::Segment> m_externalProfileBuffer;
            unsigned int m_externalProfileBufferSize;
            unsigned int m_externalProfileCycles;

            Nice::Monitor m_monitor;
    };

    /**
     * @brief Definition of the smart pointer of this class.
     */
    typedef IceUtil::Handle<Basda::MoConModule> MoConModulePtr;
}
