/* $Header: https://svn.mpia.de/gulli/TwiceAsNice/branch/unstable/TwiceAsNice/basda-mocca/src/device/mpia/mocon/Module.cc 16130 2019-11-26 14:31:10Z mathar $
*/

#include <core/Protocol.h>
#include <mocon/ConfigIDs.h>
#include <mocon/Module.h>
#include <Nice/Property/BitSet.h>
#include <Nice/Property/BridgeMemFn.hh>
#include <Basda/Mocca/Constant.h>
#include <boost/math/special_functions/round.hpp>
#include <limits>

#undef LOG_NAME
#define LOG_NAME name()

Basda::MoConModule::MoConModule(std::string _name,
        Nice::JointPtr _config,
        MPIACoreProtocolPtr _protocol) :
        MPIACoreModule(_name, _config, _protocol)
{
    addInternalProperties();
    m_protocol->addEventHandle(m_cardNo, m_moduleNo,
                               new MoConModuleEvent(_config));
}

void Basda::MoConModule::addInternalProperties()
{
    m_config->getWithDefault<Nice::Time>(
            Basda::Mocca::MoCon::cfgConnectionEventTimeout(),
            Nice::Time::milliSeconds(500), m_warning);
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgConnectionEventTimeout(), "UNIT",
            "hour");
    m_config->getWithDefault<Nice::Time>(
            Basda::Mocca::MoCon::cfgConnectionUploadTime(),
            Nice::Time::seconds(0.008541), m_warning);
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgConnectionUploadTime(), "UNIT",
            "hour");

    m_config->getWithDefault<Nice::U16>(
            Basda::Mocca::MoCon::cfgDatasheetAmplifierBitmask(), 0, m_warning);
    checkAttribute<Nice::U16>(
            Basda::Mocca::MoCon::cfgDatasheetAmplifierBitmask(),
            "MAX", 255);
    checkAttribute<Nice::U16>(
            Basda::Mocca::MoCon::cfgDatasheetAmplifierBitmask(),
            "MIN", 0);

    Nice::BitSet senseControlbs(6, 0);
    m_config->getWithDefault<Nice::BitSet>(
            Basda::Mocca::MoCon::cfgDatasheetAmplifierSenseControl(),
            senseControlbs, m_warning);
    Nice::SeqString senseControl;
    senseControl.push_back("Bit 0: PWMa / Pulse");
    senseControl.push_back("Bit 1: PWMb");
    senseControl.push_back("Bit 2: PWMc / ArRest");
    senseControl.push_back("Bit 3: Sig  / Dir");
    senseControl.push_back("Bit 4: Power Off");
    senseControl.push_back("Bit 5: Auto Power Off");
    checkAttribute<Nice::SeqString>(
            Basda::Mocca::MoCon::cfgDatasheetAmplifierSenseControl(),
            "LABEL", senseControl);

    m_config->getWithDefault<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicJerk(), 3930, m_warning);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicJerk(), "MAX",
            2147483647);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicJerk(), "MIN", 0);
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetBasicJerk(), "UNIT",
            "rev/min^3");

    m_config->getWithDefault<Nice::U16>(
            Basda::Mocca::MoCon::cfgDatasheetBasicProfile(), 0, m_warning);
    Nice::SeqString profile;
    profile.push_back("Trapeze");
    profile.push_back("Constant Velocity");
    profile.push_back("S-Curve");
    m_config->leaf(Basda::Mocca::MoCon::cfgDatasheetBasicProfile())
            ->getAttributeWithDefault<Nice::SeqString>("SELECT", profile);

    m_config->getWithDefault<Nice::U16>(
            Basda::Mocca::MoCon::cfgDatasheetBasicResolution(), 1, m_warning);
    checkAttribute<Nice::U16>(
            Basda::Mocca::MoCon::cfgDatasheetBasicResolution(), "MAX",
            8192);
    checkAttribute<Nice::U16>(
            Basda::Mocca::MoCon::cfgDatasheetBasicResolution(), "MIN",
            1);

    m_config->getWithDefault<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration(),
            1717, m_warning);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration(),
            "MAX", 2147483647);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration(),
            "MIN", 0);
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration(),
            "UNIT", "rev/min^2");

    m_config->getWithDefault<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityDeceleration(),
            1717, m_warning);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityDeceleration(),
            "MAX", 2147483647);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityDeceleration(),
            "MIN", 0);
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityDeceleration(),
            "UNIT", "rev/min^2");

    m_config->getWithDefault<double>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart(),
            0.0115, m_warning);
    checkAttribute<double>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart(),
            "MAX", 81916250.0);
    checkAttribute<double>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart(),
            "MIN", 0);
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart(),
            "UNIT", "rev/min");

    m_config->getWithDefault<double>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight(),
            0.0115, m_warning);
    checkAttribute<double>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight(),
            "MAX", 81916250.0);
    checkAttribute<double>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight(),
            "MIN", 0);
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight(),
            "UNIT", "rev/min");

    m_config->getWithDefault<Nice::I16>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalCounts(),
            1, m_warning);
    checkAttribute<Nice::I16>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalCounts(),
            "MAX", 32767);
    checkAttribute<Nice::I16>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalCounts(),
            "MIN", -32767);
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalCounts(),
            "UNIT", "counts/rev");

    m_config->getWithDefault<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalErrorLimit(),
            0, m_warning);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalErrorLimit(),
            "MAX", 2147483647);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalErrorLimit(),
            "MIN", 0);

    int encoderType = m_config->getWithDefault<int>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderType(), 0, m_warning);
    Nice::SeqString type;
    type.push_back("No Encoder");
    type.push_back("Incremental Encoder");
    type.push_back("Absolute Encoder");
    type.push_back("Incremental and Absolute Encoder");
    m_config->leaf(Basda::Mocca::MoCon::cfgDatasheetEncoderType())
            ->getAttributeWithDefault<Nice::SeqString>("SELECT", type);

    if (encoderType == Basda::EncoderType::ABSOLUTE_ENCODER
            || encoderType
                    == Basda::EncoderType::INCREMENTAL_AND_ABSOLUTE_ENCODER)
    {
        m_config->getWithDefault<Nice::U16>(
                Basda::Mocca::MoCon::cfgDatasheetEncoderAbsoluteResolution(),
                25, m_warning);
        checkAttribute<Nice::U16>(
                Basda::Mocca::MoCon::cfgDatasheetEncoderAbsoluteResolution(),
                "MAX", 29);
        checkAttribute<Nice::U16>(
                Basda::Mocca::MoCon::cfgDatasheetEncoderAbsoluteResolution(),
                "MIN", 13);
        checkAttribute<std::string>(
                Basda::Mocca::MoCon::cfgDatasheetEncoderAbsoluteResolution(),
                "UNIT", "bit");

        m_config->getWithDefault<Nice::U16>(
                Basda::Mocca::MoCon::cfgDatasheetEncoderAbsoluteCode(),
                1, m_warning);
        checkAttribute<Nice::U16>(
                Basda::Mocca::MoCon::cfgDatasheetEncoderAbsoluteCode(),
                "MAX", 1);
        checkAttribute<Nice::U16>(
                Basda::Mocca::MoCon::cfgDatasheetEncoderAbsoluteCode(),
                "MIN", 0);
        Nice::SeqString code;
        code.push_back("Binary Code");
        code.push_back("Gray Code");
        m_config->leaf(
                Basda::Mocca::MoCon::cfgDatasheetEncoderAbsoluteCode())
                ->getAttributeWithDefault<Nice::SeqString>("SELECT", code);
    }

    m_config->getWithDefault<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetMotorDockingDistance(),
            1, m_warning);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetMotorDockingDistance(),
            "MAX", 1000000000);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetMotorDockingDistance(),
            "MIN", 1);

    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSense(),
            false, m_warning);
    Nice::SeqString sense;
    sense.push_back("High Active");
    sense.push_back("Low Active");
    m_config->leaf(
            Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSense())
            ->getAttributeWithDefault<Nice::SeqString>("SELECT", sense);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSense(),
            "MAX", 1);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSense(),
            "MIN", 0);

    m_config->getWithDefault<int>(
            Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch(),
            Basda::ValueLimitSwitch::MOCON_VALUE_SWITCH_DISABLE, m_warning);
    Nice::SeqString refSwitch;
    refSwitch.push_back("Disable (default)");
    refSwitch.push_back("Positive Limit Switch");
    refSwitch.push_back("Negative Limit Switch");
    refSwitch.push_back("Separate Switch");
    refSwitch.push_back("Level Switch");
    m_config->leaf(
            Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch())
            ->getAttributeWithDefault<Nice::SeqString>("SELECT", refSwitch);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch(),
            "MAX", 4);
    checkAttribute<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch(),
            "MIN", 0);

    m_config->getWithDefault<double>(
            Basda::Mocca::MoCon::cfgDatasheetMotorVelocityDocking(),
            0.0115, m_warning);
    checkAttribute<double>(
            Basda::Mocca::MoCon::cfgDatasheetMotorVelocityDocking(),
            "MAX", 81916250.0);
    checkAttribute<double>(
            Basda::Mocca::MoCon::cfgDatasheetMotorVelocityDocking(),
            "MIN", 0);
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetMotorVelocityDocking(),
            "UNIT", "rev/min");

    m_config->getWithDefault<double>(
            Basda::Mocca::MoCon::cfgDatasheetMotorVelocityHome(),
            0.0115, m_warning);
    checkAttribute<double>(
            Basda::Mocca::MoCon::cfgDatasheetMotorVelocityHome(),
            "MAX", 81916250.0);
    checkAttribute<double>(
            Basda::Mocca::MoCon::cfgDatasheetMotorVelocityHome(),
            "MIN", 0);
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetMotorVelocityHome(),
            "UNIT", "rev/min");

    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetProduct(),
            "not defined", m_warning);

    m_config->getWithDefault<double>(
            Basda::Mocca::MoCon::cfgDatasheetTimePerCycle(),
            Basda::Constant::TIME_PER_CYCLE, m_warning); // microseconds
    checkAttribute<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetTimePerCycle(), "UNIT",
            "microsecond");

    m_config->getWithDefault<int>(
            Basda::Mocca::MoCon::cfgDatasheetTraceSampleMode(), 0, m_warning);

    m_config->getWithDefault<int>(
            Basda::Mocca::MoCon::cfgDatasheetTraceSampleRate(), 1, m_warning);
    Basda::MPIACore::checkAttribute<int>(
            Basda::Mocca::MoCon::cfgDatasheetTraceSampleRate(), "MAX",
            65000);
    Basda::MPIACore::checkAttribute<int>(
            Basda::Mocca::MoCon::cfgDatasheetTraceSampleRate(), "MIN",
            1);

    if (m_config->exist(
            Basda::Mocca::Dev::PropertyName::datasheetTravelRange()))
    {
        m_travelRange = m_config->getWithDefault<Nice::Point>(
                Basda::Mocca::Dev::PropertyName::datasheetTravelRange(),
                Nice::Point(DBL_MIN, DBL_MAX), m_warning);
        Nice::SeqString travelRange;
        travelRange.push_back("MIN");
        travelRange.push_back("MAX");
        m_config->leaf(Basda::Mocca::Dev::PropertyName::datasheetTravelRange())
                ->getAttributeWithDefault<Nice::SeqString>("SELECT",
                                                           travelRange);

        Nice::PropertyBridgeMemFn<Nice::Point, MoConModule> *p =
                new Nice::PropertyBridgeMemFn<Nice::Point, MoConModule>(
                        this, &MoConModule::travelRangeChanged);
        m_config->leaf(Basda::Mocca::Dev::PropertyName::datasheetTravelRange())
                ->applyBridge(p, m_config->name());

        if (m_travelRange.x() < -INT_MAX)
        {
            W_LOG("Negative travelrange limit (" << m_travelRange.x() << "(is less than supported hardware limit (" << -INT_MAX << "(. Values smaller than the supported hardware limit will be rejected by the MoCon. Adjust negative limit of the travelrange!")
        }
        if (m_travelRange.y() > INT_MAX)
        {
            W_LOG("Positive travelrange limit (" << m_travelRange.y() << "(is bigger than supported hardware limit (" << INT_MAX << "(. Values bigger than the supported hardware limit will be rejected by the MoCon. Adjust positive limit of the travelrange!")
        }
    }
    else
        m_travelRange = Nice::Point(NAN, NAN);

    m_config->getWithDefault<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetSegmentsPerBlock(), 5, m_warning);

    m_config->getWithDefault<std::string>(Basda::Mocca::MoCon::cfgDatasheetType(),
                              "not defined", m_warning);

    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::cfgDatasheetVendor(), "not defined", m_warning);

    m_config->getWithDefault<int>(
            Basda::Mocca::MoCon::varMoconEncoderPosition(), 0);
    m_config->getWithDefault<int>(
            Basda::Mocca::Dev::PropertyName::absoluteEncoderPosition(), 0);
    m_config->getWithDefault<int>(
            Basda::Mocca::Dev::PropertyName::incrementalEncoderPosition(), 0);

    int motorType = m_config->getWithDefault<int>(
            Basda::Mocca::MoCon::cfgDatasheetMotorType(),
            Basda::MotorType::SERVO, m_warning);
    Nice::SeqString motorTypeLabel;
    motorTypeLabel.push_back("Servo");
    motorTypeLabel.push_back("Stepper");
    m_config->leaf(Basda::Mocca::MoCon::cfgDatasheetMotorType())
            ->getAttributeWithDefault<Nice::SeqString>("SELECT",
                                                       motorTypeLabel);
    switch (motorType)
    {
        case Basda::MotorType::SERVO:
            m_config->getWithDefault<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopBias(),
                    0, m_warning);
            checkAttribute<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopBias(),
                    "MAX", 100);
            checkAttribute<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopBias(),
                    "MIN", -100);
            checkAttribute<std::string>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopBias(),
                    "UNIT", "%");

            m_config->getWithDefault<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopILim(),
                    0, m_warning);
            checkAttribute<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopILim(),
                    "MAX", 2147483647);
            checkAttribute<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopILim(),
                    "MIN", 0);

            m_config->getWithDefault<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKAFF(),
                    0, m_warning);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKAFF(),
                    "MAX", 32767);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKAFF(),
                    "MIN", 0);

            m_config->getWithDefault<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKD(),
                    0, m_warning);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKD(),
                    "MAX", 32767);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKD(),
                    "MIN", 0);

            m_config->getWithDefault<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKI(),
                    0, m_warning);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKI(),
                    "MAX", 32767);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKI(),
                    "MIN", 0);

            m_config->getWithDefault<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKOUT(),
                    0, m_warning);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKOUT(),
                    "MAX", 100);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKOUT(),
                    "MIN", 0);
            checkAttribute<std::string>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKOUT(),
                    "UNIT", "%");

            m_config->getWithDefault<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKP(),
                    0, m_warning);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKP(),
                    "MAX", 32767);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKP(),
                    "MIN", 0);

            m_config->getWithDefault<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKVFF(),
                    0, m_warning);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKVFF(),
                    "MAX", 32767);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKVFF(),
                    "MIN", 0);

            m_config->getWithDefault<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopLimit(),
                    0, m_warning);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopLimit(),
                    "MAX", 100);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopLimit(),
                    "MIN", 0);
            checkAttribute<std::string>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopLimit(),
                    "UNIT", "%");

            checkAttribute<std::string>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicResolution(),
                    "UNIT", "counts/rev");
            if (m_config->exist(
                    Basda::Mocca::Dev::PropertyName::datasheetTravelRange()))
            {
                checkAttribute<std::string>(
                        Basda::Mocca::Dev::PropertyName::datasheetTravelRange(),
                        "UNIT", "counts");
            }
            m_config->leaf(Basda::Mocca::MoCon::varMoconEncoderPosition())
                    ->applyAttribute<std::string>("UNIT", "counts");
            break;
        case Basda::MotorType::STEPPER:
            m_config->getWithDefault<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsPosition(),
                    1, m_warning);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsPosition(),
                    "MAX", 16);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsPosition(),
                    "MIN", 1);

            m_config->getWithDefault<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsValue(),
                    1, m_warning);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsValue(),
                    "MAX", 1024);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsValue(),
                    "MIN", 0);

            m_config->getWithDefault<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsBitvalue(),
                    0, m_warning);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsBitvalue(),
                    "MAX", 255);
            checkAttribute<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsBitvalue(),
                    "MIN", 0);

            m_config->getWithDefault<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalSteps(),
                    1, m_warning);
            checkAttribute<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalSteps(),
                    "MAX", 32767);
            checkAttribute<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalSteps(),
                    "MIN", -32767);
            checkAttribute<std::string>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalSteps(),
                    "UNIT", "steps/rev");

            m_config->getWithDefault<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperAutoPowerOff(),
                    false, m_warning);
            m_config->getWithDefault<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsAdaption(),
                    false, m_warning);
            m_config->getWithDefault<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue(),
                    1, m_warning);
            checkAttribute<std::string>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicResolution(),
                    "UNIT", "steps/rev");
            if (m_config->exist(
                    Basda::Mocca::Dev::PropertyName::datasheetTravelRange()))
            {
                checkAttribute<std::string>(
                        Basda::Mocca::Dev::PropertyName::datasheetTravelRange(),
                        "UNIT", "steps");
            }
            m_config->leaf(Basda::Mocca::MoCon::varMoconEncoderPosition())
                    ->applyAttribute<std::string>("UNIT", "steps");
            break;
    }
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusPhasingInitialized(), false);
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusAtMaxVelocity(), false);
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusTracking(), false);
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusCurrentProfileMode(), false);
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusAxisSettled(), false);
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusMotorOn(), false);
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusPositionCapture(), false);
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusInMotion(), false);
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusInPositiveLimit(), false);
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusInNegativeLimit(), false);
    m_config->getWithDefault<bool>(
            Basda::Mocca::MoCon::varActivityStatusLimitProfileSegment(), false);

    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusEncoderA(),
    		false);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusEncoderB(),
    		false);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusEncoderIndex(),
    		false);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusHomeSwitch(),
    		false);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusPositiveLimit(),
    		false);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusNegativeLimit(),
    		false);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusAxisIn(),
    		false);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusHallA(),
    		false);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusHallB(),
    		false);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusHallC(),
    		false);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varSignalStatusAxisOut(),
    		false);

    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleClassification(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierCardIdentification(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierCardManufactureDate(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierCardName(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierCardOffset(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierCardSerialNumber(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierCardVersion(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleAutoPowerOffInverse(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleBreakPowerOffInverse(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleClassification(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleFuse(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleIdentification(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleMotorPowerSupply(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleName(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModulePWMA(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModulePWMB(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModulePWMC(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleShortCurrentFlag(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleSignDirInverse(),
            "not defined");
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varAmplifierModuleThermalFlag(),
            "not defined");
    m_config->getWithDefault<double>(Basda::Mocca::MoCon::varFirmwareChipset(),
                         MOCON_COS_VERSION_NUMBER);
    m_config->getWithDefault<double>(Basda::Mocca::MoCon::varFirmwareModule(),
                         MOCON_CONTROLLER_VERSION_NUMBER);
    m_config->getWithDefault<std::string>(
            Basda::Mocca::MoCon::varFirmwareVersion(),
            "COS_XC161 V2.17, Jan 24 2011");
    m_config->getWithDefault<int>(Basda::Mocca::MoCon::varMcControlledAxis(), 0);
    m_config->getWithDefault<int>(Basda::Mocca::Dev::PropertyName::limit(), 0); //0 - not in limit;
    //+/-1 - software limit;
    //+/-2 - hardware limit
    m_config->getWithDefault<std::string>(Basda::Mocca::MoCon::varMcError(),
                              "not defined");
    m_config->getWithDefault<int>(Basda::Mocca::MoCon::varMcMotorType(), 0);
    m_config->getWithDefault<int>(Basda::Mocca::MoCon::varMcVersion(), 0);
    m_config->getWithDefault<bool>(Basda::Mocca::MoCon::varMotionComplete(),
                       true);
//    m_config->getWithDefault<bool>(Basda::Mocca::Dev::PropertyName::motionError(),
//                       false);
    m_config->getWithDefault<bool>(Basda::Mocca::Dev::PropertyName::moving(), false);
    m_config->getWithDefault<bool>(Basda::Mocca::Dev::PropertyName::atHome(), false);
    m_config->getWithDefault<int>(Basda::Mocca::Dev::PropertyName::velocity(), 0);
    m_config->leaf(Basda::Mocca::Dev::PropertyName::velocity())
            ->applyAttribute<std::string>("UNIT", "rev/min");

    m_config->getWithDefault<Nice::I64>(
            Basda::Mocca::MoCon::varTimeReferenceMoCon(), 0);
    m_config->getWithDefault<Nice::Date>(
            Basda::Mocca::MoCon::varTimeReferenceServer(),
            Nice::Date());
    m_config->getWithDefault<Nice::I64>(
            Basda::Mocca::MoCon::varTimeCurrentMoCon(), 0);
    m_config->getWithDefault<Nice::Date>(
            Basda::Mocca::MoCon::varTimeCurrentServer(),
            Nice::Date());

    m_config->getWithDefault<double>(Basda::Mocca::MoCon::varTimeCycle(), 1.0);
    m_config->leaf(Basda::Mocca::MoCon::varTimeCycle())
            ->applyAttribute<std::string>("UNIT", "microseconds");
    m_config->leaf(Basda::Mocca::MoCon::varTimeCycle())
            ->applyAttribute<int>("PREC", 9);

//         chekProperty<double>("VAR.TRACE.DATA.ACTIVITY_STATUS_REGISTER", 0);
//         chekProperty<double>("VAR.TRACE.DATA.ACTUAL_POSITION", 0);
//         chekProperty<double>("VAR.TRACE.DATA.ACTUAL_VELOCITY", 0);
//         chekProperty<double>("VAR.TRACE.DATA.CAPTURE_REGISTER", 0);
//         chekProperty<double>("VAR.TRACE.DATA.CHIPSET_TIME", 0);
//         chekProperty<double>("VAR.TRACE.DATA.COMMANDED_ACCELERATION", 0);
//         chekProperty<double>("VAR.TRACE.DATA.COMMANDED_POSITION", 0);
//         chekProperty<double>("VAR.TRACE.DATA.COMMANDED_VELOCITY", 0);
//         chekProperty<double>("VAR.TRACE.DATA.DERIVATIVE", 0);
//         chekProperty<double>("VAR.TRACE.DATA.EVENT_STATUS_REGISTER", 0);
//         chekProperty<double>("VAR.TRACE.DATA.INTEGRAL", 0);
//         chekProperty<double>("VAR.TRACE.DATA.MOTOR_COMMAND", 0);
//         chekProperty<double>("VAR.TRACE.DATA.PID_ERROR", 0);
//         chekProperty<double>("VAR.TRACE.DATA.POSITION_ERROR", 0);
//         chekProperty<double>("VAR.TRACE.DATA.SIGNAL_STATUS_REGISTER", 0);
//
// //     m_config->setAtNode<bool>("VAR.CFG.CHANGED", false);
// //     m_config->setAtNode<bool>("VAR.CFG.SYNCH", false);
// //     m_config->setAtNode<bool>("VAR.INITIALIZED", false);
//

    m_cycleTime = m_config->node(
            Basda::Mocca::MoCon::cfgDatasheetTimePerCycle())
            ->get<double>();
    m_cycleTime =
            m_cycleTime != 0.0 ? m_cycleTime : Basda::Constant::TIME_PER_CYCLE;

    m_extendedProfileParamter = true;
    m_externalProfileIndexCycle = 0;

    m_collisionPositive = false;
    m_collisionNegative = false;
}

void Basda::MoConModule::chat(const unsigned int _cardNo,
        const unsigned int _commandID,
        const unsigned int _moduleNo,
        const unsigned int _selectID,
        const std::string _parameter,
        const int _numberOfLines)
{
    W_LOG("Deprecated method! chat on card " << m_cardNo << " module " << m_moduleNo);
    m_protocol->chat(_commandID, _selectID, _cardNo, _moduleNo, _parameter,
                     _numberOfLines);
}

void Basda::MoConModule::dontParse(std::string &_ret)
{
    W_LOG("Deprecated method! dontParse");
    m_protocol->dontParse(_ret);
}

void Basda::MoConModule::receiveDataRaw(const unsigned int _cardNo,
        const unsigned int _commandID,
        const unsigned int _moduleNo,
        std::string &_ret,
        const unsigned int _numberOfLines)
{
    W_LOG("Deprecated method! receiveData");
    m_protocol->receiveDataRaw(_commandID, _cardNo, _moduleNo, _ret,
                               _numberOfLines);
}

void Basda::MoConModule::setBasicSettings(const Basda::SelectBasicSettings::Constant _selectID,
        const double _parameter)
{
    D_LOG("setBasicSettings on card " << m_cardNo << " module " << m_moduleNo << " _selectID " << _selectID << " _parameter " << _parameter);
    std::string errorMsg;

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_SET_BASIC_SETTINGS, _selectID,
                        m_cardNo, m_moduleNo, _parameter);
//        m_config->node("VAR.INITIALIZED")->set<bool>(false);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

int Basda::MoConModule::sharkDerotatorBacklashProcedure(int procedure)
{
    int result = EXIT_FAILURE;
    try
    {
        const int supplementary_module = 6;
        U7_LOG("1 23 6 ________# ReserveModule");
        m_protocol->set(Basda::Cmd::MPIA_RESERVE_MOD, Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST, m_cardNo, supplementary_module);
        usleep(1000000);

        U7_LOG("1 112 6 3 1 ___# SetStepperSettings AutopowerOff 1");
        m_protocol->set(Basda::Cmd::MOCON_SET_STEPPER_SETTINGS, Basda::SelectStepperSettings::MOCON_SELECT_AUTO_POWER_OFF, m_cardNo, supplementary_module, 1);
        usleep(1000000);

        U7_LOG("1 120 6 _______# Motor Initialize");
        m_protocol->set(Basda::Cmd::MOCON_MOTOR_INITIALIZE, Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST, m_cardNo, supplementary_module);
        usleep(5000000);

        U7_LOG("1 123 5 65536 _# MoveNStepsCount 65536");
        m_protocol->set(Basda::Cmd::MOCON_MOVE_N_STEPS_COUNTS, Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST, m_cardNo, m_moduleNo, 65536);
        usleep(2000000);

        U7_LOG("1 123 5 65536 _# MoveNStepsCount 65536");
        m_protocol->set(Basda::Cmd::MOCON_MOVE_N_STEPS_COUNTS, Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST, m_cardNo, m_moduleNo, 65536);
        usleep(2000000);

        U7_LOG("1 112 6 3 0 ___# SetStepperSettings AutoPowerOff 0");
        m_protocol->set(Basda::Cmd::MOCON_SET_STEPPER_SETTINGS, Basda::SelectStepperSettings::MOCON_SELECT_AUTO_POWER_OFF, m_cardNo, supplementary_module, 0);
        usleep(1000000);

        U7_LOG("1 120 6 _______# Motor Initilize");
        m_protocol->set(Basda::Cmd::MOCON_MOTOR_INITIALIZE, Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST, m_cardNo, supplementary_module);
        usleep(5000000);

        U7_LOG("1 24 6 ________# FreeModule");
        m_protocol->set(Basda::Cmd::MPIA_FREE_MOD, Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST, m_cardNo, supplementary_module);
        usleep(1000000);
        result = EXIT_SUCCESS;
        U8_LOG("Derotator Antibacklash Procedure Successfully completed");
    }
    catch(...)
    {
        E_LOG(__FUNCTION__);
        throw;
    }
    return result;
}


void Basda::MoConModule::setBasicSettings()
{
    D_LOG("set all BasicSettings on card " << m_cardNo << " module " << m_moduleNo);
    double tmp = 0;

    setBasicSettings(
            Basda::SelectBasicSettings::MOCON_SELECT_PROFILE,
            m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicProfile()));

    if ((tmp = m_config->getAtNode<Nice::U16>(
            Basda::Mocca::MoCon::cfgDatasheetBasicResolution()))
            > 0)
        setBasicSettings(
		    Basda::SelectBasicSettings::MOCON_SELECT_COUNTS_PER_REVOLUTION,
		    tmp);
    else
    {
        W_LOG("Basic resolution (" << m_config->node(Basda::Mocca::MoCon::cfgDatasheetBasicResolution())->path() << ") will not be uploaded because it has a invalid setting: " << tmp)
    }

    if ((tmp = m_config->getAtNode<double>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight()))
            > 0)
        setBasicSettings(Basda::SelectBasicSettings::MOCON_SELECT_VELOCITY,
                         tmp);
    else
    {
        W_LOG("Basic velocity straight (" << m_config->node(Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight())->path() << ") will not be uploaded because it has a invalid setting: " << tmp)
    }

    if (m_config->getAtNode<int>(
            Basda::Mocca::MoCon::cfgDatasheetMotorType())
            == Basda::MotorType::STEPPER) // servo does not have a basic velocity start
//            && (tmp =
//                    m_config->getAtNode<double>(
//                            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart())
//                            > 0))
        setBasicSettings(
                Basda::SelectBasicSettings::MOCON_SELECT_START_VELOCITY,
                m_config->getAtNode<double>(
                        Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart()));

    if ((tmp =
            m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration()))
                    > 0)
        setBasicSettings(Basda::SelectBasicSettings::MOCON_SELECT_ACCELERATION,
                         tmp);
    else
    {
        W_LOG("Basic acceleration (" << m_config->node(Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration())->path() << ") will not be uploaded because it has a invalid setting: " << tmp)
    }

    if ((tmp =
            m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityDeceleration()))
                    > 0)
        setBasicSettings(Basda::SelectBasicSettings::MOCON_SELECT_DECELERATION,
                         tmp);
    else
    {
        W_LOG("Basic deceleration (" << m_config->node(Basda::Mocca::MoCon::cfgDatasheetBasicVelocityDeceleration())->path() << ") will not be uploaded because it has a invalid setting: " << tmp)
    }

    if ((tmp = m_config->getAtNode<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicJerk())) > 0)
        setBasicSettings(Basda::SelectBasicSettings::MOCON_SELECT_JERK, tmp);
    else
    {
        W_LOG("Basic jerk (" << m_config->node(Basda::Mocca::MoCon::cfgDatasheetBasicJerk())->path() << ") will not be uploaded because it has a invalid setting: " << tmp)
    }
}

void Basda::MoConModule::getBasicSettings(bool _compareParameter)
{
    D_LOG("getBasicSettings of card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        bool warning = false;
        std::stringstream warningMsg;
        std::string ret;

        m_protocol->get(Basda::Cmd::MOCON_GET_BASIC_SETTINGS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);

        std::vector<double> basicSettings = getVector<double>(ret);

        if (_compareParameter)
        {
            if ((Nice::U16)basicSettings.at(1) != m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicProfile()))
            {
                warningMsg << "Mocon internal basic profile value differs from "
                        "the value in the configuration file ("
                        << (Nice::U16)basicSettings.at(1) << " != "
                        << m_config->getAtNode<Nice::U16>(
                                Basda::Mocca::MoCon::cfgDatasheetBasicProfile())
                        << ")! ";
                warning = true;
            }

            if ((Nice::U16)basicSettings.at(3) != m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicResolution()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal basic resolution value differs from "
                        "the value in the configuration file ("
                        << (Nice::U16)basicSettings.at(3) << " != "
                        << m_config->getAtNode<Nice::U16>(
                                Basda::Mocca::MoCon::cfgDatasheetBasicResolution())
                        << ")! ";
                warning = true;
            }

            if (basicSettings.at(5) != m_config->getAtNode<double>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal basic velocity straight value differs from "
                        "the value in the configuration file ("
                        << basicSettings.at(5) << " != "
                        << m_config->getAtNode<double>(
                                Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight())
                        << ")! ";
                warning = true;
            }

            if (basicSettings.at(7) != m_config->getAtNode<double>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal basic velocity start value differs from "
                        "the value in the configuration file ("
                        << basicSettings.at(7) << " != "
                        << m_config->getAtNode<double>(
                                Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart())
                        << ")! ";
                warning = true;
            }

            if ((Nice::U32)basicSettings.at(9) != m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal basic velocity acceleration value differs from "
                        "the value in the configuration file ("
                        << (Nice::U32)basicSettings.at(9) << " != "
                        << m_config->getAtNode<Nice::U32>(
                                Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration())
                        << ")! ";
                warning = true;
            }

            if ((Nice::U32)basicSettings.at(11) != m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityDeceleration()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal basic velocity deceleration value differs from "
                        "the value in the configuration file ("
                        << (Nice::U32)basicSettings.at(11) << " != "
                        << m_config->getAtNode<Nice::U32>(
                                Basda::Mocca::MoCon::cfgDatasheetBasicVelocityDeceleration())
                        << ")! ";
                warning = true;
            }

            if ((Nice::U32)basicSettings.at(13) != m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicJerk()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal basic jerk value differs from "
                        "the value in the configuration file ("
                        << (Nice::U32)basicSettings.at(13) << " != "
                        << m_config->getAtNode<Nice::U32>(
                                Basda::Mocca::MoCon::cfgDatasheetBasicJerk())
                        << ")! ";
                warning = true;
            }

            if (warning)
            {
                W_LOG(warningMsg.str());
            }
        }

        // MoCon config parameter will be saved only when a dump of the
        // config files is requested or during the init an upload is not required.
        // compare parameter & upload parameter              -> values are NOT stored in the property tree (init case)
        // compare parameter & download (!upload) parameter  -> values are stored in the property tree (init case)
        // !compare parameter & upload parameter             -> values are stored in the property tree (dump case)
        // !compare parameter & download (!upload) parameter -> values are stored in the property tree (dump case)
        if (!(_compareParameter && configParameterUploadRequired()))
        {
            m_config->setAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicProfile(),
                    (Nice::U16) basicSettings.at(1));
            m_config->setAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicResolution(),
                    (Nice::U16) basicSettings.at(3));
            m_config->setAtNode<double>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight(),
                    basicSettings.at(5));
            m_config->setAtNode<double>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart(),
                    basicSettings.at(7));
            m_config->setAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration(),
                    (Nice::U32) basicSettings.at(9));
            m_config->setAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityDeceleration(),
                    (Nice::U32) basicSettings.at(11));
            m_config->setAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicJerk(),
                    (Nice::U32) basicSettings.at(13));
        }
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::validateBasicSettings()
{
    D_LOG("validateBasicSettings of card " << m_cardNo << " module " << m_moduleNo);

    bool error = false;
    std::stringstream errorMsg;

    if (m_config->getAtNode<Nice::U16>(
            Basda::Mocca::MoCon::cfgDatasheetBasicResolution()) == 0)
    {
        errorMsg << "Motor not correctly configured! Basic resolution ("
                << m_config->node(
                        Basda::Mocca::MoCon::cfgDatasheetBasicResolution())
                        ->path() << ") has an invalid value: "
                << m_config->getAtNode<Nice::U16>(
                        Basda::Mocca::MoCon::cfgDatasheetBasicResolution());
        error = true;
    }

    if (m_config->getAtNode<double>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight()) == 0)
    {
        if (errorMsg.str().length())
            errorMsg << std::endl;
        errorMsg << "Motor not correctly configured! Basic velocity ("
                << m_config->node(
                        Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight())
                        ->path() << ") has an invalid value: "
                << m_config->getAtNode<double>(
                        Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight());
        error = true;
    }

    // Servo motor don't need the velocity start configuration value.
    // Servo motor configuration set this value to zero just for
    // compatibility to stepper motor configuration.
    // For Stepper configuration this value could be zero.
    if (m_config->getAtNode<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration())
            == 0)
    {
        if (errorMsg.str().length())
            errorMsg << std::endl;
        errorMsg << "Motor not correctly configured! Basic acceleration ("
                << m_config->node(
                        Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration())
                        ->path() << ") has an invalid value: "
                << m_config->getAtNode<Nice::U32>(
                        Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration());
        error = true;
    }

    // If the deceleration value is set to zero than the MoCon uses the
    // acceleration value as deceleration value. Therefore this value could
    // be zero.

    if (error)
    {
        F_THROW(Basda::MoCon::ParamMissingException, errorMsg.str());
    }
}

void Basda::MoConModule::setMotorSettings(const Basda::SelectMotorSettings::Constant _selectID,
        const double _parameter)
{
    D_LOG("setMotorSettings on card " << m_cardNo << " module " << m_moduleNo << " _selectID " << _selectID << " _parameter " << _parameter);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_SET_MOTOR_SETTINGS, _selectID,
                        m_cardNo, m_moduleNo, _parameter);
//        m_config->node("VAR.INITIALIZED")->set<bool>(false);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::setMotorSettings()
{
    D_LOG("set all MotorSettings on card " << m_cardNo << " module " << m_moduleNo);

    setMotorSettings(
            Basda::SelectMotorSettings::MOCON_SELECT_REFERENCE_SWITCH,
            m_config->getAtNode<int>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch()));
    setMotorSettings(
            Basda::SelectMotorSettings::MOCON_SELECT_REFERENCE_SENSE,
            m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSense()));
    setMotorSettings(
            Basda::SelectMotorSettings::MOCON_SELECT_HOME_VELOCITY,
            m_config->getAtNode<double>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorVelocityHome()));
    setMotorSettings(
            Basda::SelectMotorSettings::MOCON_SELECT_DOCKING_VELOCITY,
            m_config->getAtNode<double>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorVelocityDocking()));
    setMotorSettings(
            Basda::SelectMotorSettings::MOCON_SELECT_DOCKING_DISTANCE,
            m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorDockingDistance()));
}

void Basda::MoConModule::getMotorSettings(bool _compareParameter)
{
    D_LOG("getMotorSettings of card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        bool warning = false;
        std::stringstream warningMsg;
        std::string ret;

        m_protocol->get(Basda::Cmd::MOCON_GET_MOTOR_SETTINGS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);

        std::vector<double> motorSettings = getVector<double>(ret);

        if (_compareParameter)
        {
            if ((int)motorSettings.at(1) != m_config->getAtNode<int>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch()))
            {
                warningMsg << "Mocon internal motor reference switch value differs from "
                        "the value in the configuration file ("
                        << (int)motorSettings.at(1) << " != "
                        << m_config->getAtNode<int>(
                                Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch())
                        << ")!";
                warning = true;
            }

            if ((bool)motorSettings.at(3) != m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSense()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal motor reference sense value differs from "
                        "the value in the configuration file ("
                        << (bool)motorSettings.at(3) << " != "
                        << m_config->getAtNode<bool>(
                                Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSense())
                        << ")!";
                warning = true;
            }

            if (motorSettings.at(5) != m_config->getAtNode<double>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorVelocityHome()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal motor velocity home value differs from "
                        "the value in the configuration file ("
                        << motorSettings.at(5) << " != "
                        << m_config->getAtNode<double>(
                                Basda::Mocca::MoCon::cfgDatasheetMotorVelocityHome())
                        << ")!";
                warning = true;
            }

            if (motorSettings.at(7) != m_config->getAtNode<double>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorVelocityDocking()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal motor velocity docking value differs from "
                        "the value in the configuration file ("
                        << motorSettings.at(7) << " != "
                        << m_config->getAtNode<double>(
                                Basda::Mocca::MoCon::cfgDatasheetMotorVelocityDocking())
                        << ")!";
                warning = true;
            }

            if ((Nice::U32)motorSettings.at(9) != m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorDockingDistance()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal motor docking distance value differs from "
                        "the value in the configuration file ("
                        << (Nice::U32)motorSettings.at(9) << " != "
                        << m_config->getAtNode<Nice::U32>(
                                Basda::Mocca::MoCon::cfgDatasheetMotorDockingDistance())
                        << ")!";
                warning = true;
            }

            if (warning)
            {
                W_LOG(warningMsg.str());
            }
        }

        // MoCon config parameter will be saved only when a dump of the
        // config files is requested or during the init an upload is not required.
        // compare parameter & upload parameter              -> values are NOT stored in the property tree (init case)
        // compare parameter & download (!upload) parameter  -> values are stored in the property tree (init case)
        // !compare parameter & upload parameter             -> values are stored in the property tree (dump case)
        // !compare parameter & download (!upload) parameter -> values are stored in the property tree (dump case)
        if (!(_compareParameter && configParameterUploadRequired()))
        {
            m_config->setAtNode<int>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch(),
                    (int) motorSettings.at(1));
            m_config->setAtNode<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSense(),
                    (bool) motorSettings.at(3));
            m_config->setAtNode<double>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorVelocityHome(),
                    motorSettings.at(5));
            m_config->setAtNode<double>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorVelocityDocking(),
                    motorSettings.at(7));
            m_config->setAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetMotorDockingDistance(),
                    (Nice::U32) motorSettings.at(9));
        }
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

int Basda::MoConModule::getMotorType()
{
    return m_config->getAtNode<int>(
            Basda::Mocca::MoCon::cfgDatasheetMotorType());
}

void Basda::MoConModule::setStepperSettings(const Basda::SelectStepperSettings::Constant _selectID,
        const int _parameter)
{
    D_LOG("setStepperSettings on card " << m_cardNo << " module " << m_moduleNo << " _selectID " << _selectID << " _parameter " << _parameter);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_SET_STEPPER_SETTINGS, _selectID,
                        m_cardNo, m_moduleNo, _parameter);
//        m_config->node("VAR.INITIALIZED")->set<bool>(false);

        checkTravelRange();
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::setStepperSettings()
{
    D_LOG("setStepperSettings on card " << m_cardNo << " module " << m_moduleNo);

    setStepperSettings(
            Basda::SelectStepperSettings::MOCON_SELECT_MICRO_STEPS,
            m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue()));
    setStepperSettings(
            Basda::SelectStepperSettings::MOCON_SELECT_MICRO_STEPS_ADAPTION,
            m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsAdaption()));
    setStepperSettings(
            Basda::SelectStepperSettings::MOCON_SELECT_AUTO_POWER_OFF,
            m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperAutoPowerOff()));

    m_microsteps = m_config->getAtNode<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue());

    checkTravelRange();
}

void Basda::MoConModule::getStepperSettings(bool _compareParameter)
{
    // the stepper settings will be read to
    bool warning = false;
    std::stringstream warningMsg;
    std::string ret = "";
    std::vector<int> stepperSettings(6, 0);
    try
    {
        m_protocol->get(Basda::Cmd::MOCON_GET_STEPPER_SETTINGS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);

        std::vector<int> stepperSettings = getVector<int>(ret);

        if (_compareParameter)
        {
            if ((Nice::U32)stepperSettings.at(1) != m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue()))
            {
                warningMsg << "Mocon internal stepper microsteps value differs from "
                        "the value in the configuration file ("
                        << (Nice::U32)stepperSettings.at(1) << " != "
                        << m_config->getAtNode<Nice::U32>(
                                Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue())
                        << ")!";
                warning = true;
            }

            if ((bool)stepperSettings.at(3) != m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsAdaption()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal stepper microsteps adaption value differs from "
                        "the value in the configuration file ("
                        << (bool)stepperSettings.at(3) << " != "
                        << m_config->getAtNode<bool>(
                                Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsAdaption())
                        << ")!";
                warning = true;
            }

            if ((bool)stepperSettings.at(5) != m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperAutoPowerOff()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal stepper auto power off value differs from "
                        "the value in the configuration file ("
                        << (bool)stepperSettings.at(5) << " != "
                        << m_config->getAtNode<bool>(
                                Basda::Mocca::MoCon::cfgDatasheetStepperAutoPowerOff())
                        << ")!";
                warning = true;
            }
            if (warning)
            {
                W_LOG(warningMsg.str());
            }
        }

        // MoCon config parameter will be saved only when a dump of the
        // config files is requested or during the init an upload is not required.
        // compare parameter & upload parameter              -> values are NOT stored in the property tree (init case)
        // compare parameter & download (!upload) parameter  -> values are stored in the property tree (init case)
        // !compare parameter & upload parameter             -> values are stored in the property tree (dump case)
        // !compare parameter & download (!upload) parameter -> values are stored in the property tree (dump case)
        if (!(_compareParameter && configParameterUploadRequired()))
        {
            m_microsteps = (Nice::U32) stepperSettings.at(1);
            m_config->setAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue(),
                    (Nice::U32) stepperSettings.at(1));
            m_config->setAtNode<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsAdaption(),
                    (bool) stepperSettings.at(3));
            m_config->setAtNode<bool>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperAutoPowerOff(),
                    (bool) stepperSettings.at(5));
        }

        checkTravelRange();
    }

    catch (Basda::MoCon::CmdForStepperException &e)
    {
        std::stringstream errorMsg;
        errorMsg << "The module " << m_moduleNo << " on card " << m_cardNo
                << " is a servo!";
        E_THROW( ::Basda::MoCon::CmdForStepperException, e, errorMsg.str());
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::checkTravelRange()
{
    Nice::U32 datasheetStepperMicrostepsValue = m_config->getAtNode<Nice::U32>(
            Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue());
    bool datasheetStepperMicrostepsAdaption = m_config->getAtNode<bool>(
                        Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsAdaption());

    if (!datasheetStepperMicrostepsAdaption)
        datasheetStepperMicrostepsValue = 1;

    bool error = false;
    std::stringstream errorMsg;
    if (!isnan(m_travelRange.x()) && (int)m_travelRange.x() * (int)datasheetStepperMicrostepsValue < INT_MIN )
    {
//        W_LOG("Negative travelrange limit (" << (int)m_travelRange.x() << ") is less than supported hardware limit (" << INT_MIN / (int)datasheetStepperMicrostepsValue << "). Values smaller than the supported hardware limit will be rejected by the MoCon or will lead to an internal integer overrun. Adjust negative limit of the travelrange!")
//        W_LOG("Minimal addressable position is -INT_MAX / datasheetStepperMicrostepsValue: " << INT_MIN << " / " << (int)datasheetStepperMicrostepsValue << " = " << INT_MIN / (int)datasheetStepperMicrostepsValue)
        errorMsg << "Negative travelrange limit (" << (int)m_travelRange.x() << ") is less than supported hardware limit (" << INT_MIN / (int)datasheetStepperMicrostepsValue << "). Values smaller than the supported hardware limit will be rejected by the MoCon or will lead to an internal integer overrun. Adjust negative limit of the travelrange! ";
        errorMsg << "Minimal addressable position is -INT_MAX / datasheetStepperMicrostepsValue: " << INT_MIN << " / " << (int)datasheetStepperMicrostepsValue << " = " << INT_MIN / (int)datasheetStepperMicrostepsValue << ". ";
        error = true;
    }
    if (!isnan(m_travelRange.y()) && (int)m_travelRange.y() * (int)datasheetStepperMicrostepsValue > INT_MAX)
    {
//        W_LOG("Positive travelrange limit (" << (int)m_travelRange.y() << ") is bigger than supported hardware limit (" << INT_MAX / (int)datasheetStepperMicrostepsValue << "). Values bigger than the supported hardware limit will be rejected by the MoCon or will lead to an internal integer overrun. Adjust positive limit of the travelrange!")
//        W_LOG("Maximal addressable position is INT_MAX / datasheetStepperMicrostepsValue: " << INT_MAX << " / " << (int)datasheetStepperMicrostepsValue << " = " << INT_MAX / (int)datasheetStepperMicrostepsValue)
        errorMsg << "Positive travelrange limit (" << (int)m_travelRange.y() << ") is bigger than supported hardware limit (" << INT_MAX / (int)datasheetStepperMicrostepsValue << "). Values bigger than the supported hardware limit will be rejected by the MoCon or will lead to an internal integer overrun. Adjust positive limit of the travelrange! ";
        errorMsg << "Maximal addressable position is INT_MAX / datasheetStepperMicrostepsValue: " << INT_MAX << " / " << (int)datasheetStepperMicrostepsValue << " = " << INT_MAX / (int)datasheetStepperMicrostepsValue;
        error = true;
    }
    if (error)
    {
        F_THROW(::Basda::MoCon::OutOfRangeException, errorMsg.str())
    }
}

void Basda::MoConModule::setServoLoopSettings(const Basda::SelectServoLoopSettings::Constant _selectID,
        const unsigned int _parameter)
{
    D_LOG("setServoLoopSettings on card " << m_cardNo << " module " << m_moduleNo << " _selectID " << _selectID << " _parameter " << _parameter);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_SET_SERVO_LOOP_SETTINGS, _selectID,
                        m_cardNo, m_moduleNo, _parameter);
//        m_config->node("VAR.INITIALIZED")->set<bool>(false);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::setServoLoopSettings()
{
    D_LOG("setServoLoopSettings on card " << m_cardNo << " module " << m_moduleNo);

    setServoLoopSettings(
            Basda::SelectServoLoopSettings::MOCON_SELECT_KP,
            m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKP()));
    setServoLoopSettings(
            Basda::SelectServoLoopSettings::MOCON_SELECT_KI,
            m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKI()));
    setServoLoopSettings(
            Basda::SelectServoLoopSettings::MOCON_SELECT_KD,
            m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKD()));
    setServoLoopSettings(
            Basda::SelectServoLoopSettings::MOCON_SELECT_KAFF,
            m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKAFF()));
    setServoLoopSettings(
            Basda::SelectServoLoopSettings::MOCON_SELECT_KVFF,
            m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKVFF()));
    setServoLoopSettings(
            Basda::SelectServoLoopSettings::MOCON_SELECT_KOUT,
            m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKOUT()));
    setServoLoopSettings(
            Basda::SelectServoLoopSettings::MOCON_SELECT_ILIM,
            m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopILim()));
    setServoLoopSettings(
            Basda::SelectServoLoopSettings::MOCON_SELECT_BIAS,
            m_config->getAtNode<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopBias()));
    setServoLoopSettings(
            Basda::SelectServoLoopSettings::MOCON_SELECT_LIMIT,
            m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopLimit()));
}

void Basda::MoConModule::getServoLoopSettings(bool _compareParameter)
{
    D_LOG("getServoLoopSettings on card " << m_cardNo << " module " << m_moduleNo);

    bool warning = false;
    std::stringstream warningMsg;
    std::string ret = "";
    std::vector<int> servoLoopSettings(18, 0);
    try
    {
        m_protocol->get(Basda::Cmd::MOCON_GET_SERVO_LOOP_SETTINGS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);
        servoLoopSettings = getVector<int>(ret);

        if (_compareParameter)
        {
            if ((Nice::U16)servoLoopSettings.at(1) != m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKP()))
            {
                warningMsg << "Mocon internal servo loop KP value differs from "
                        "the value in the configuration file ("
                        << (Nice::U16)servoLoopSettings.at(1) << " != "
                        << m_config->getAtNode<Nice::U16>(
                                Basda::Mocca::MoCon::cfgDatasheetServoLoopKP())
                        << ")!";
                warning = true;
            }

            if ((Nice::U16)servoLoopSettings.at(3) != m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKI()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal servo loop KI value differs from "
                        "the value in the configuration file ("
                        << (Nice::U16)servoLoopSettings.at(3) << " != "
                        << m_config->getAtNode<Nice::U16>(
                                Basda::Mocca::MoCon::cfgDatasheetServoLoopKI())
                        << ")!";
                warning = true;
            }

            if ((Nice::U16)servoLoopSettings.at(5) != m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKD()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal servo loop KD value differs from "
                        "the value in the configuration file ("
                        << (Nice::U16)servoLoopSettings.at(5) << " != "
                        << m_config->getAtNode<Nice::U16>(
                                Basda::Mocca::MoCon::cfgDatasheetServoLoopKD())
                        << ")!";
                warning = true;
            }

            if ((Nice::U16)servoLoopSettings.at(7) != m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKAFF()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal servo loop KAFF value differs from "
                        "the value in the configuration file ("
                        << (Nice::U16)servoLoopSettings.at(7) << " != "
                        << m_config->getAtNode<Nice::U16>(
                                Basda::Mocca::MoCon::cfgDatasheetServoLoopKAFF())
                        << ")!";
                warning = true;
            }

            if ((Nice::U16)servoLoopSettings.at(9) != m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKVFF()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal servo loop KVFF value differs from "
                        "the value in the configuration file ("
                        << (Nice::U16)servoLoopSettings.at(9) << " != "
                        << m_config->getAtNode<Nice::U16>(
                                Basda::Mocca::MoCon::cfgDatasheetServoLoopKVFF())
                        << ")!";
                warning = true;
            }

            if ((Nice::U16)servoLoopSettings.at(11) != m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKOUT()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal servo loop KOUT value differs from "
                        "the value in the configuration file ("
                        << (Nice::U16)servoLoopSettings.at(11) << " != "
                        << m_config->getAtNode<Nice::U16>(
                                Basda::Mocca::MoCon::cfgDatasheetServoLoopKOUT())
                        << ")!";
                warning = true;
            }

            if ((Nice::U32)servoLoopSettings.at(13) != m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopILim()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal servo loop ILim value differs from "
                        "the value in the configuration file ("
                        << (Nice::U32)servoLoopSettings.at(13) << " != "
                        << m_config->getAtNode<Nice::U32>(
                                Basda::Mocca::MoCon::cfgDatasheetServoLoopILim())
                        << ")!";
                warning = true;
            }

            if ((Nice::Short)servoLoopSettings.at(15) != m_config->getAtNode<Nice::Short>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopBias()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal servo loop Bias value differs from "
                        "the value in the configuration file ("
                        << (Nice::Short)servoLoopSettings.at(15) << " != "
                        << m_config->getAtNode<Nice::Short>(
                                Basda::Mocca::MoCon::cfgDatasheetServoLoopBias())
                        << ")!";
                warning = true;
            }

            if ((Nice::U16)servoLoopSettings.at(17) != m_config->getAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopLimit()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal servo loop Limit value differs from "
                        "the value in the configuration file ("
                        << (Nice::U16)servoLoopSettings.at(17) << " != "
                        << m_config->getAtNode<Nice::U16>(
                                Basda::Mocca::MoCon::cfgDatasheetServoLoopLimit())
                        << ")!";
                warning = true;
            }

            if (warning)
            {
                W_LOG(warningMsg.str());
            }
        }

        // MoCon config parameter will be saved only when a dump of the
        // config files is requested or during the init an upload is not required.
        // compare parameter & upload parameter              -> values are NOT stored in the property tree (init case)
        // compare parameter & download (!upload) parameter  -> values are stored in the property tree (init case)
        // !compare parameter & upload parameter             -> values are stored in the property tree (dump case)
        // !compare parameter & download (!upload) parameter -> values are stored in the property tree (dump case)
        if (!(_compareParameter && configParameterUploadRequired()))
        {
            m_config->setAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKP(),
                    (Nice::U16) servoLoopSettings.at(1));
            m_config->setAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKI(),
                    (Nice::U16) servoLoopSettings.at(3));
            m_config->setAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKD(),
                    (Nice::U16) servoLoopSettings.at(5));
            m_config->setAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKAFF(),
                    (Nice::U16) servoLoopSettings.at(7));
            m_config->setAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKVFF(),
                    (Nice::U16) servoLoopSettings.at(9));
            m_config->setAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopKOUT(),
                    (Nice::U16) servoLoopSettings.at(11));
            m_config->setAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopILim(),
                    (Nice::U32) servoLoopSettings.at(13));
            m_config->setAtNode<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopBias(),
                    (Nice::I16) servoLoopSettings.at(15));
            m_config->setAtNode<Nice::U16>(
                    Basda::Mocca::MoCon::cfgDatasheetServoLoopLimit(),
                    (Nice::U16) servoLoopSettings.at(17));
        }
    }

    catch (Basda::MoCon::CmdForServoException &e)
    {
        std::stringstream errorMsg;
        errorMsg << "The module " << m_moduleNo << " on card " << m_cardNo
                << " is a stepper!";
        E_THROW( ::Basda::MoCon::CmdForServoException, e, errorMsg.str());
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    catch (std::out_of_range &e)
    {
        F_THROW(::Basda::MoCon::VectorRangeCheckException, "Vector out of range exception!")
    }
}

void Basda::MoConModule::setEncoderSettings(const Basda::SelectSetEncodeSettings::Constant _selectID,
        const int _parameter)
{
    D_LOG("setEncoderSettings on card " << m_cardNo << " module " << m_moduleNo << " _selectID " << _selectID << " _parameter " << _parameter);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_SET_ENCODER_SETTINGS, _selectID,
                        m_cardNo, m_moduleNo, _parameter);
//        m_config->node("VAR.INITIALIZED")->set<bool>(false);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::setEncoderSettings()
{
    D_LOG("set all encoder settings on card " << m_cardNo << " module " << m_moduleNo);
    Nice::U32 tmp;

    if ((tmp =
            m_config->getAtNode<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalCounts()))
            > 0)
        setEncoderSettings(
                Basda::SelectSetEncodeSettings::MOCON_SELECT_INC_COUNTS, tmp);
    if (m_config->getAtNode<int>(
            Basda::Mocca::MoCon::cfgDatasheetMotorType())
            == Basda::MotorType::STEPPER)
        setEncoderSettings(
                Basda::SelectSetEncodeSettings::MOCON_SELECT_STEPS_PER_REVOLUTION,
                m_config->getAtNode<Nice::I16>(
                        Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalSteps()));
    if ((tmp =
            m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalErrorLimit()))
            > 0)
        setEncoderSettings(
                Basda::SelectSetEncodeSettings::MOCON_SELECT_ERROR_LIMIT, tmp);
}

void Basda::MoConModule::getEncoderSettings(bool _compareParameter)
{
    D_LOG("getEncoderSettings of card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        bool warning = false;
        std::stringstream warningMsg;
        std::string ret;

        m_protocol->get(Basda::Cmd::MOCON_GET_ENCODER_SETTINGS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);

        std::vector<int> encoderSettings = getVector<int>(ret);

        if (_compareParameter)
        {
            if ((Nice::I16)encoderSettings.at(1) != m_config->getAtNode<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalCounts()))
            {
                warningMsg << "Mocon internal encoder incremental counts value differs from "
                        "the value in the configuration file ("
                        << (Nice::I16)encoderSettings.at(1) << " != "
                        << m_config->getAtNode<Nice::I16>(
                                Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalCounts())
                        << ")!";
                warning = true;
            }

            if ((Nice::I16)encoderSettings.at(3) != m_config->getAtNode<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalSteps()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal encoder incremental steps value differs from "
                        "the value in the configuration file ("
                        << (Nice::I16)encoderSettings.at(3) << " != "
                        << m_config->getAtNode<Nice::I16>(
                                Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalSteps())
                        << ")!";
                warning = true;
            }

            if ((Nice::U32)encoderSettings.at(5) != m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalErrorLimit()))
            {
                if (warningMsg.str().length())
                    warningMsg << std::endl;
                warningMsg << "Mocon internal encoder incremental error limit value differs from "
                        "the value in the configuration file ("
                        << (Nice::U32)encoderSettings.at(5) << " != "
                        << m_config->getAtNode<Nice::U32>(
                                Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalErrorLimit())
                        << ")!";
                warning = true;
            }

            if (warning)
            {
                W_LOG(warningMsg.str());
            }
        }

        // MoCon config parameter will be saved only when a dump of the
        // config files is requested or during the init an upload is not required.
        // compare parameter & upload parameter              -> values are NOT stored in the property tree (init case)
        // compare parameter & download (!upload) parameter  -> values are stored in the property tree (init case)
        // !compare parameter & upload parameter             -> values are stored in the property tree (dump case)
        // !compare parameter & download (!upload) parameter -> values are stored in the property tree (dump case)
        if (!(_compareParameter && configParameterUploadRequired()))
        {
            m_config->setAtNode<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalCounts(),
                    (Nice::I16) encoderSettings.at(1));
            m_config->setAtNode<Nice::I16>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalSteps(),
                    (Nice::I16) encoderSettings.at(3));
            m_config->setAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetEncoderIncrementalErrorLimit(),
                    (Nice::U32)encoderSettings.at(5));
        }
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    catch (std::out_of_range &e)
    {
        F_THROW(::Basda::MoCon::VectorRangeCheckException, "Vector out of range exception!")
    }
}

void Basda::MoConModule::setAmplifierSettings(const Basda::SelectAmplifierSettings::Constant _selectID,
        const int _parameter1,
        const int _parameter2,
        const int _parameter3)
{
    D_LOG("setAmplifierSettings on card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        std::stringstream str;
        str << _parameter1 << " " << _parameter2 << " " << _parameter3;

        if (_selectID
                == Basda::SelectAmplifierSettings::MOCON_SELECT_MICROSTEPS_ALLOCATION)
            m_protocol->set(Basda::Cmd::MOCON_SET_AMPLIFIER_SETTINGS, _selectID,
                            m_cardNo, m_moduleNo, str.str());
        else
            m_protocol->set(Basda::Cmd::MOCON_SET_AMPLIFIER_SETTINGS, _selectID,
                            m_cardNo, m_moduleNo, _parameter1);
//        m_config->node("VAR.INITIALIZED")->set<bool>(false);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::setAmplifierSettings()
{
    D_LOG("set all AmplifierSettings on card " << m_cardNo << " module " << m_moduleNo);

    setAmplifierSettings(
            Basda::SelectAmplifierSettings::MOCON_SELECT_SENSE_CONTROL_SIGNAL,
            m_config->getAtNode<int>(
                    Basda::Mocca::MoCon::cfgDatasheetAmplifierSenseControl()));
    if (m_config->getAtNode<int>(
            Basda::Mocca::MoCon::cfgDatasheetMotorType())
            == Basda::MotorType::STEPPER)
    {
        setAmplifierSettings(
                Basda::SelectAmplifierSettings::MOCON_SELECT_BIT_MASK_MICROSTEPS,
                m_config->getAtNode<Nice::U16>(
                        Basda::Mocca::MoCon::cfgDatasheetAmplifierBitmask()));
        setAmplifierSettings(
                Basda::SelectAmplifierSettings::MOCON_SELECT_MICROSTEPS_ALLOCATION,
                m_config->getAtNode<Nice::U16>(
                        Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsPosition()),
                m_config->getAtNode<Nice::U16>(
                        Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsValue()),
                m_config->getAtNode<Nice::U16>(
                        Basda::Mocca::MoCon::cfgDatasheetAmplifierMicrostepsBitvalue()));
    }
}

void Basda::MoConModule::getAmplifierCardInfo()
{
    D_LOG("getAmplifierCardInfo of card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        std::string ret;
        std::string str;
        int id;

        m_protocol->get(Basda::Cmd::MOCON_GET_AMP_CARD_INFO,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);

        std::vector<std::string> amplifier;
        std::stringstream ss(ret);

        while (ss >> id >> std::ws)
        {
            std::getline(ss, str);
            amplifier.push_back(str);
        }
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleClassification(),
                amplifier.at(0));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierCardIdentification(),
                amplifier.at(1));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierCardName(),
                amplifier.at(2));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierCardVersion(),
                amplifier.at(3));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierCardManufactureDate(),
                amplifier.at(4));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierCardSerialNumber(),
                amplifier.at(5));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierCardOffset(),
                amplifier.at(6));
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    catch (std::out_of_range &e)
    {
        F_THROW(::Basda::MoCon::VectorRangeCheckException, "Vector out of range exception!")
    }
}

void Basda::MoConModule::getAmplifierInfo()
{
    D_LOG("getAmplifierInfo of card " << m_cardNo << " module " << m_moduleNo);
    std::multimap<std::string, std::string> mm;

    try
    {
        std::string ret;
        std::string str;
        int id;

        m_protocol->get(Basda::Cmd::MOCON_GET_AMPLIFIER_INFO,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);

        std::vector<std::string> amplifier;
        std::stringstream ss(ret);

        while (ss >> id >> std::ws)
        {
            std::getline(ss, str);
            amplifier.push_back(str);
        }

        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleClassification(),
                amplifier.at(0));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleIdentification(),
                amplifier.at(1));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleName(),
                amplifier.at(2));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleMotorPowerSupply(),
                amplifier.at(3));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleFuse(),
                amplifier.at(4));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleThermalFlag(),
                amplifier.at(5));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleShortCurrentFlag(),
                amplifier.at(6));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModulePWMA(),
                amplifier.at(7));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModulePWMB(),
                amplifier.at(8));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModulePWMC(),
                amplifier.at(9));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleSignDirInverse(),
                amplifier.at(10));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleBreakPowerOffInverse(),
                amplifier.at(11));
        m_config->setAtNode<std::string>(
                Basda::Mocca::MoCon::varAmplifierModuleAutoPowerOffInverse(),
                amplifier.at(12));

        if (amplifier.at(3) == "break")
        {
            E_THROW(Basda::MoCon::AmplifierPowerSupplyException, "Broken amplifier motor power supply.")
        }

        if (amplifier.at(4) == "break")
        {
            E_THROW(Basda::MoCon::AmplifierFuseException, "Broken amplifier fuse.")
        }

        if (amplifier.at(5) == "Yes")
        {
            E_THROW(Basda::MoCon::AmplifierThermalException, "Critical amplifier temperature.")
        }

        if (amplifier.at(6) == "Yes")
        {
            E_THROW(Basda::MoCon::AmplifierShortCurrentException, "Amplifier short current.")
        }
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    catch (std::out_of_range &e)
    {
        F_THROW(::Basda::MoCon::VectorRangeCheckException, "Vector out of range exception!")
    }
}

void Basda::MoConModule::getMotorControllerVersion()
{
    D_LOG("getMotorControllerVersion of card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        std::string ret;

        m_protocol->get(Basda::Cmd::MOCON_GET_MC_VERSION,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);

        int motorType;
        int axis;
        int tmp;
        int version;
        sscanf(ret.c_str(), "0x%2x%1x%1x%4x", &motorType, &axis, &tmp,
               &version);

        m_config->setAtNode<int>(
                Basda::Mocca::MoCon::varMcMotorType(), motorType);
        m_config->setAtNode<int>(
                Basda::Mocca::MoCon::varMcControlledAxis(), axis);
        m_config->setAtNode<int>(Basda::Mocca::MoCon::varMcVersion(),
                                 version);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

std::string Basda::MoConModule::getMotorControllerErrorNr()
{
    D_LOG("getMotorControllerErrorNr of card " << m_cardNo << " module " << m_moduleNo);

    std::string ret;

    m_protocol->get(Basda::Cmd::MOCON_GET_MC_ERROR,
                    Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST, m_cardNo,
                    m_moduleNo, ret);

    m_config->setAtNode<std::string>(
            Basda::Mocca::MoCon::varMcError(), ret);
    return ret;
}

void Basda::MoConModule::initializeMotor()
{
    D_LOG("initialize motor of card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_MOTOR_INITIALIZE,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo);
//        m_config->node("VAR.INITIALIZED")->set<bool>(true);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::abort()
{
    D_LOG("abort on card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_ABRUPT_STOP,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::stop()
{
    D_LOG("stop on card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_SMOOTH_STOP,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

double Basda::MoConModule::moveToNegativeLimit(bool _travelRangeCheck)
{
    if (!m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::varActivityStatusMotorOn()))
    {
        E_LOG("Motor is off. Motion command will be ignored.")
        E_THROW(::Basda::MoCon::MotorOffException, "Motor is off. Motion command will be ignored.")
    }

    int distance = 0;
    if (!_travelRangeCheck || isnan(m_travelRange.x()))
    {
        if (m_config->getAtNode<int>(
                Basda::Mocca::MoCon::cfgDatasheetMotorType())
                == Basda::MotorType::STEPPER)
        {
            Nice::U32 datasheetStepperMicrostepsValue = m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue());
            bool datasheetStepperMicrostepsAdaption = m_config->getAtNode<bool>(
                                Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsAdaption());

            if (!datasheetStepperMicrostepsAdaption)
                datasheetStepperMicrostepsValue = 1;

            distance = -INT_MAX / datasheetStepperMicrostepsValue;
        }
        else
            distance = -INT_MAX;

        try
        {
            // MoCon can only go the INT_MAX in absolute position
            // position behind that position can not be addressed
            m_protocol->set(Basda::Cmd::MOCON_MOVE_N_ABS_STEPS_COUNTS,
                            Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                            m_cardNo, m_moduleNo, distance);
        }

        catch (Basda::MoCon::CheckSumException &e)
        {
            E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
        }
    }
    else
    {
        distance = (int) m_travelRange.x();
        moveAbsolute((int) m_travelRange.x());
    }
    // return is necessary to compute the completion
    return distance;
}

double Basda::MoConModule::moveToPositiveLimit(bool _travelRangeCheck)
{
    if (!m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::varActivityStatusMotorOn()))
    {
        E_LOG("Motor is off. Motion command will be ignored.")
        E_THROW(::Basda::MoCon::MotorOffException, "Motor is off. Motion command will be ignored.")
    }

    int distance = 0;
    if (!_travelRangeCheck || isnan(m_travelRange.y()))
    {
        if (m_config->getAtNode<int>(
                Basda::Mocca::MoCon::cfgDatasheetMotorType())
                == Basda::MotorType::STEPPER)
        {
            Nice::U32 datasheetStepperMicrostepsValue = m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue());
            bool datasheetStepperMicrostepsAdaption = m_config->getAtNode<bool>(
                                Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsAdaption());

            if (!datasheetStepperMicrostepsAdaption)
                datasheetStepperMicrostepsValue = 1;

            distance = INT_MAX / datasheetStepperMicrostepsValue;
        }
        else
            distance = INT_MAX;

        try
        {
            // MoCon can anly go the INT_MAX in absolute position
            // position behind that position can not be addressed
            m_protocol->set(Basda::Cmd::MOCON_MOVE_N_ABS_STEPS_COUNTS,
                            Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                            m_cardNo, m_moduleNo, distance);
        }

        catch (Basda::MoCon::CheckSumException &e)
        {
            E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
        }
    }
    else
    {
        distance = (int) m_travelRange.y();
        moveAbsolute(distance);
    }
    // return is necessary to compute the completion
    return distance;
}

double Basda::MoConModule::moveOutOfLimit()
{
    D_LOG("moveOutOffLimit on card " << m_cardNo << " module " << m_moduleNo);

    if (!m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::varActivityStatusMotorOn()))
    {
        E_LOG("Motor is off. Motion command will be ignored.")
        E_THROW(::Basda::MoCon::MotorOffException, "Motor is off. Motion command will be ignored.")
    }

    int limit = isAtLimit();
    Nice::U32 distance = m_config->node(
            Basda::Mocca::MoCon::cfgDatasheetMotorDockingDistance())
            ->get<Nice::U32>();
    int d = 0;

    if (limit > Basda::Limit::SOFTWARE_LIMIT) // the motor needs to move out also in case the software limit is the same as the harware limit
        d = -distance;
    else if (limit < -Basda::Limit::SOFTWARE_LIMIT) // the motor needs to move out also in case the software limit is the same as the harware limit
        d = distance;

    // if the motor is in valid range it is required
    // to move the motor by 0 in order to receive the
    // completion event from the MoCon in order to complete the
    // command
    try
    {
        m_protocol->set(Basda::Cmd::MOCON_MOVE_N_STEPS_COUNTS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, d);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
    return d;
}

void Basda::MoConModule::moveAbsolute(int _absolutePosition)
{
    D_LOG("moveToAbsolutePosition on card " << m_cardNo << " module " << m_moduleNo << " " << _absolutePosition);
    if (!m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::varActivityStatusMotorOn()))
    {
        E_LOG("Motor is off. Motion command will be ignored.")
        E_THROW(::Basda::MoCon::MotorOffException, "Motor is off. Motion command will be ignored.")
    }

    if (!isnan(m_travelRange.x())
            && _absolutePosition < (int) m_travelRange.x())
    {
        E_THROW(::Basda::MoCon::OutOfRangeException, "Position value (" << _absolutePosition << ") of motor " << name() << " is less then minimum software limit (" << (int) m_travelRange.x() << ").")
//        D_LOG("Position value (" << _absolutePosition << ") is less then minimum software limit (" << m_travelRange.x() << "). Adjust value to " << m_travelRange.x())
//        _absolutePosition = (int) m_travelRange.x();
    }
    if (!isnan(m_travelRange.y())
            && _absolutePosition > (int) m_travelRange.y())
    {
        E_THROW(::Basda::MoCon::OutOfRangeException, "Position value (" << _absolutePosition << ") of motor " << name() << " is bigger then maximum software limit (" << (int) m_travelRange.y() << ").")
//        D_LOG("Position value (" << _absolutePosition << ") is bigger then maximum software limit (" << m_travelRange.y() << "). Adjust value to " << m_travelRange.y())
//        _absolutePosition = (int) m_travelRange.y();
    }

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_MOVE_N_ABS_STEPS_COUNTS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, _absolutePosition);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::moveRelative(int _relativePosition)
{
    D_LOG("moveToRelativePosition on card " << m_cardNo << " module " << m_moduleNo);

    if (!m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::varActivityStatusMotorOn()))
    {
        E_LOG("Motor is off. Motion command will be ignored.")
        E_THROW(::Basda::MoCon::MotorOffException, "Motor is off. Motion command will be ignored.")
    }

    int absolutePosition;

    absolutePosition = m_currentPosition + _relativePosition;

    if (!isnan(m_travelRange.x()) && absolutePosition < (int) m_travelRange.x())
    {
        E_THROW(::Basda::MoCon::OutOfRangeException, "Position value (" << absolutePosition << ") of motor " << name() << " is less then minimum software limit (" << (int) m_travelRange.x() << ").")
//        D_LOG("Position value (" << absolutePosition << ") is less then minimum software limit (" << m_travelRange.x() << "). Adjust value to " << m_travelRange.x())
//        _relativePosition = (int) m_travelRange.x() - m_currentPosition;
    }

    if (!isnan(m_travelRange.y()) && absolutePosition > (int) m_travelRange.y())
    {
        E_THROW(::Basda::MoCon::OutOfRangeException, "Position value (" << absolutePosition << ") of motor " << name() << " is bigger then maximum software limit (" << (int) m_travelRange.y() << ").")
//        D_LOG("Position value (" << absolutePosition << ") is bigger then maximum software limit (" << m_travelRange.y() << "). Adjust value to " << m_travelRange.y())
//        _relativePosition = (int) m_travelRange.y() - m_currentPosition;
    }

    if (absolutePosition < INT_MIN || absolutePosition > INT_MAX)
    {
        E_THROW(::Basda::MoCon::OutOfRangeException, "Target position will be not addressable by the MoCon. Addressable positions are ["
                                                     << INT_MIN << ", " << INT_MAX << "]. Requested absolute position would be " << absolutePosition << ".")
    }

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_MOVE_N_STEPS_COUNTS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, _relativePosition);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::moveToHome()
{
    D_LOG("moveToHome on card " << m_cardNo << " module " << m_moduleNo);

    if (!m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::varActivityStatusMotorOn()))
    {
        E_LOG("Motor is off. Motion command will be ignored.")
        E_THROW(::Basda::MoCon::MotorOffException, "Motor is off. Motion command will be ignored.")
    }

    int referenceSwitch = m_config->getAtNode<int>(
            Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch());
    if (referenceSwitch > Basda::ValueLimitSwitch::MOCON_VALUE_SWITCH_DISABLE
            && referenceSwitch
                    <= Basda::ValueLimitSwitch::MOCON_VALUE_SWITCH_LEVEL)
    {
//        if (!isnan(m_travelRange.x())
//                && 0 < (int) m_travelRange.x())
//        {
//            E_THROW(::Basda::MoCon::OutOfRangeException, "Home position is less then minimum software limit (" << m_travelRange.x() << "). Please correct the travelrange!")
//        }
//        if (!isnan(m_travelRange.y())
//                && 0 > (int) m_travelRange.y())
//        {
//            E_THROW(::Basda::MoCon::OutOfRangeException, "Home position is bigger then maximum software limit (" << m_travelRange.y() << "). Please correct the travelrange!")
//        }

        try
        {
            m_protocol->set(Basda::Cmd::MOCON_MOVE_FIND_HOME,
                            Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                            m_cardNo, m_moduleNo);
        }

        catch (Basda::MoCon::CheckSumException &e)
        {
            E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
        }
    }
    else
    {
        std::string errorMsg =
                "Motor settings incomplete. Home search is not available. Motor reference switch is not defined or disabled. Check property " + m_config->node(
                        Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch())->path() + ". ";
        E_THROW(::Basda::MoCon::MotorSettingsIncompleteException, errorMsg);
    }
}

void Basda::MoConModule::moveCorrection()
{
    D_LOG("moveCorrection on card " << m_cardNo << " module " << m_moduleNo);

    if (!m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::varActivityStatusMotorOn()))
    {
        E_LOG("Motor is off. Motion command will be ignored.")
        E_THROW(::Basda::MoCon::MotorOffException, "Motor is off. Motion command will be ignored.")
    }

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_MOVE_ADAPTION_POS_TO_ENC,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

#if 0
bool Basda::MoConModule::checkMotionError()
{
    return m_config->getAtNode<bool>(
            Basda::Mocca::Dev::PropertyName::motionError());
}

void Basda::MoConModule::resetMotionError()
{
    m_config->setAtNode<bool>(
            Basda::Mocca::Dev::PropertyName::motionError(), false);
}
#endif /* 0 */

bool Basda::MoConModule::isMoving()
{
    D_LOG("isMoving on card " << m_cardNo << " module " << m_moduleNo);

    bool isMoving = false;

    try
    {
        std::string ret;
        ret.clear();
        m_protocol->get(Basda::Cmd::MOCON_GET_IN_MOTION_FLAG,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);
        isMoving = getValue<bool>(ret);
        m_config->setAtNode<bool>(Basda::Mocca::Dev::PropertyName::moving(),
                                  isMoving);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    return isMoving;
}

bool Basda::MoConModule::isAtHome()
{
    D_LOG("isAtHome on card " << m_cardNo << " module " << m_moduleNo);

    bool isAtHome = false;
//    int limit;

//    try
//    {
//        std::string ret;
//        ret.clear();
//        int referenceSwitch = m_config->getWithDefault<int>(
//                    Basda::Mocca::MoCon::cfgDatasheetMotorReferenceSwitch(),
//                    0);
//        switch (referenceSwitch)
//        {
//            case 0:
//                isAtHome = false;
//                break;
//            case 1:
//                limit = isAtLimit();
//                if (limit > 0)
//                    isAtHome = true;
//                break;
//            case 2:
//                limit = isAtLimit();
//                if (limit < 0)
//                    isAtHome = true;
//                break;
//            case 3:
//            [m_cycleTime 00:00:00.000611]
    Nice::BitSet signalStatus(11, 0);
//                signalStatus.value = getSignalStatus();
//                isAtHome = signalStatus[3];
//                break;
//            case 4:
//
//                break;
//        }
//        m_config->setAtNode<bool>(Basda::Mocca::Dev::PropertyName::atHome(),
//                                  isAtHome);
//    }
//
//    catch (Basda::MoCon::CheckSumException &e)
//    {
//        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
//    }

    return isAtHome;
}

bool Basda::MoConModule::isMotionComplete()
{
//	Nice::Guard guard (m_mutex);
    bool motionComplete = m_config->getAtNode<bool>(Basda::Mocca::MoCon::varMotionComplete());
    D_LOG("isMotionComplete on card " << m_cardNo << " module " << m_moduleNo << " motion complete: " << motionComplete);

    return motionComplete;
}

void Basda::MoConModule::setMotionComplete(bool _complete)
{
//	Nice::Guard guard (m_mutex);
    D_LOG("setMotionComplete on card " << m_cardNo << " module " << m_moduleNo << ": " << _complete);

        m_config->setAtNode<bool>(Basda::Mocca::MoCon::varMotionComplete(), _complete);
}

void Basda::MoConModule::setCollision(bool _collisionNegative, bool _collisionPositive)
{
    m_collisionPositive = _collisionPositive;
    m_collisionNegative = _collisionNegative;
}

int Basda::MoConModule::isAtLimit()
{
    D_LOG("isAtLimit on card " << m_cardNo << " module " << m_moduleNo);

    int status = Basda::Limit::IN_VALID_RANGE;

    try
    {
        std::string ret;
        unsigned int isAtLimit = Basda::ResponseLimitSwitch::MOCON_RESPONSE_SWITCH_NOT_IN_LIMIT;

        if (!m_collisionPositive && !m_collisionNegative)
        {
            m_protocol->get(Basda::Cmd::MOCON_GET_LIMIT_SWITCH_FLAG,
                            Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                            m_cardNo, m_moduleNo, ret);

            isAtLimit = getValue<unsigned int>(ret);

            switch (isAtLimit)
            {
                case Basda::ResponseLimitSwitch::MOCON_RESPONSE_SWITCH_NOT_IN_LIMIT:
                    if (!isnan(m_travelRange.x())
                            && Nice::Helper::fuzzyCompare(m_currentPosition,
                                                          m_travelRange.x()))
                    {
                        status = -Basda::Limit::SOFTWARE_LIMIT;
                        m_config->setAtNode<int>(
                                Basda::Mocca::Dev::PropertyName::limit(), status);
                    }
                    else if (!isnan(m_travelRange.y())
                            && Nice::Helper::fuzzyCompare(m_currentPosition,
                                                          m_travelRange.y()))
                    {
                        status = Basda::Limit::SOFTWARE_LIMIT;
                        m_config->setAtNode<int>(
                                Basda::Mocca::Dev::PropertyName::limit(), status);
                    }
                    else
                    {
                        m_config->setAtNode<int>(
                                Basda::Mocca::Dev::PropertyName::limit(),
                                Basda::Limit::IN_VALID_RANGE);
                    }
                    break;
                case Basda::ResponseLimitSwitch::MOCON_RESPONSE_SWITCH_POSITIVE_LIMIT:
                    status = Basda::Limit::HARDWARE_LIMIT;
                    m_config->setAtNode<int>(
                            Basda::Mocca::Dev::PropertyName::limit(), status);
                    break;
                case Basda::ResponseLimitSwitch::MOCON_RESPONSE_SWITCH_NEGATIVE_LIMIT:
                    status = -Basda::Limit::HARDWARE_LIMIT;
                    m_config->setAtNode<int>(
                            Basda::Mocca::Dev::PropertyName::limit(), status);
                    break;
                case Basda::ResponseLimitSwitch::MOCON_RESPONSE_SWITCH_WRONG_LIMIT:
                    std::string errorMsg =
                            "Limit switch settings are wrong, broken cable or collision detected."
                                    " (If no limits are in use, bridge the limit switches with ground!)";
                    E_THROW(::Basda::MoCon::LimitSwitchException, errorMsg);
                    break;
            }
        }
        else
        {
            if (m_collisionPositive && m_collisionNegative)
            {
                status = Basda::Limit::COLLISION_TWO_SIDED;
                m_config->setAtNode<int>(
                        Basda::Mocca::Dev::PropertyName::limit(), status);
            }
            else if (m_collisionPositive)
            {
                status = Basda::Limit::COLLISION_ONE_SIDED;
                m_config->setAtNode<int>(
                        Basda::Mocca::Dev::PropertyName::limit(), status);
            }
            else if (m_collisionNegative)
            {
                status = -Basda::Limit::COLLISION_ONE_SIDED;
                m_config->setAtNode<int>(
                        Basda::Mocca::Dev::PropertyName::limit(), status);
            }
            else
            {
                W_LOG("Unknown collision state.")
                m_config->setAtNode<int>(
                        Basda::Mocca::Dev::PropertyName::limit(),
                        Basda::Limit::IN_VALID_RANGE);
            }
        }
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    return status;
}

unsigned int Basda::MoConModule::getActivityStatus()
{
    D_LOG("getActivityStatus of card " << m_cardNo << " module " << m_moduleNo);

    unsigned int activityStatus = 0;
    try
    {
        std::string ret;

        m_protocol->get(Basda::Cmd::MOCON_GET_ACTIVITY_STATUS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);

        std::stringstream ss;
        ss << ret;
        ss >> std::hex >> activityStatus;
		std::bitset<16> bs(activityStatus);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusPhasingInitialized(),
						bs[0]);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusAtMaxVelocity(),
						bs[1]);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusTracking(),
						bs[2]);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusCurrentProfileMode(),
						bs[3]);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusAxisSettled(),
						bs[7]);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusMotorOn(),
						bs[8]);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusPositionCapture(),
						bs[9]);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusInMotion(),
						bs[10]);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusInPositiveLimit(),
						bs[11]);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusInNegativeLimit(),
						bs[12]);
		m_config->setAtNode<bool>(
						Basda::Mocca::MoCon::varActivityStatusLimitProfileSegment(),
						bs[13]);

		if (!bs[8])
		{
			std::stringstream errorMsg;
			errorMsg << "Motor " << name() << " (module " << m_moduleNo
					<< " of card " << m_cardNo << " ("
					<< m_config->getAtNode<std::string>(Basda::Mocca::MoCon::cfgConnectionAddress())
					<< ") was switched off due to a motion error. "
					   "Stop the movement of ALL motors that are connected to "
					   "that MoCon card, especially when other services are "
					   "using the same MoCon card but leave the services running! "
					   "Finally do a hardware reset of the MoCon or "
					   "a software reset via the command '1 8 0'. Services might "
					   "reconnect automatically and position values should be restored. "
					   "No initialization or homing is necessary.";

			E_THROW(::Basda::MoCon::MotorOffException, errorMsg.str() )
		}
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    return activityStatus;
}

unsigned int Basda::MoConModule::getSignalStatus()
{
    D_LOG("getSignalStatus of card " << m_cardNo << " module " << m_moduleNo);

    unsigned int signalStatus = 0;
    try
    {
        std::string ret;
        m_protocol->get(Basda::Cmd::MOCON_GET_SIGNAL_STATUS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);

        std::stringstream ss;
        ss << ret;
        ss >> std::hex >> signalStatus;
		std::bitset<16> bs(signalStatus);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusEncoderA(),
						bs[0]);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusEncoderB(),
						bs[1]);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusEncoderIndex(),
						bs[2]);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusHomeSwitch(),
						bs[3]);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusPositiveLimit(),
						bs[4]);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusNegativeLimit(),
						bs[5]);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusAxisIn(),
						bs[6]);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusHallA(),
						bs[7]);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusHallB(),
						bs[8]);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusHallC(),
						bs[9]);
		m_config->setAtNode<bool>(
		                Basda::Mocca::MoCon::varSignalStatusAxisOut(),
						bs[10]);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    return signalStatus;
}

int Basda::MoConModule::getMEncPosition()
{
    D_LOG("getMEncPosition of card " << m_cardNo << " module " << m_moduleNo);

    int positionInSteps = 0;

    try
    {
        std::string ret;

        m_protocol->get(Basda::Cmd::MOCON_GET_CURRENT_POSITION,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);
        positionInSteps = getValue<int>(ret);
        m_config->setAtNode<int>(Basda::Mocca::MoCon::varMoconEncoderPosition(),
                                 positionInSteps);
        // store the current position in order to know it for the move commands (move commands don't need to ask again for the current position)
        m_currentPosition = positionInSteps;
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    return positionInSteps;
}

int Basda::MoConModule::getAEncPosition()
{
    D_LOG("getAEncPosition of card " << m_cardNo << " module " << m_moduleNo);

    int aEncPosition = 0;
    int encoderType = 0;
    encoderType = m_config->getAtNode<int>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderType());

    // there is no way to figure out if a absolute encoder is connected to the MoCon
    // we have to trust the configuration
    // if this command is called and the configuration is not configured for a
    // absolute encoder, an exception will be thrown and the absolute encoder
    // position will be set to zero
    if (encoderType == Basda::EncoderType::ABSOLUTE_ENCODER
            || encoderType
                    == Basda::EncoderType::INCREMENTAL_AND_ABSOLUTE_ENCODER)
    {
        try
        {
            std::string ret;

            // I already have changed the MoCon firmware. Now, the firmware can handle both,
            // the grey code and the binary code. But final testing has not been completed yet.
            // Therefore, I would still need a couple of days to double-check the firmware
            // together with the absolute encoder provided to me. I will keep you updated.
            // The GetAEncActualPosition command has changed from:
            // <CardNo> 171 <MotorNo>
            // to:
            // <CardNo> 171 <MotorNo> <ResolutionBit> <GreyCode>
            // ResolutionBit: Encoder resolution (13bit - 29bit); Default: 25
            // GreyCode: 0 = Binary Code; 1 = Grey Code; Default: 1
            // Both of the parameters above are optional in order to be backward compatible.
            Nice::U16 resolution =
                    m_config->getAtNode<Nice::U16>(
                            Basda::Mocca::MoCon::cfgDatasheetEncoderAbsoluteResolution());
            Nice::U16 code =
                    m_config->getAtNode<Nice::U16>(
                            Basda::Mocca::MoCon::cfgDatasheetEncoderAbsoluteCode());

            std::stringstream str;
            str << resolution << " " << code;

            m_protocol->get(Basda::Cmd::MOCON_GET_AENC_ACTUAL_POSITION,
                            Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                            m_cardNo, m_moduleNo, ret, str.str());
            aEncPosition = getValue<int>(ret);
            m_config->setAtNode<int>(
                    Basda::Mocca::Dev::PropertyName::absoluteEncoderPosition(),
                    aEncPosition);
        }

        catch (Basda::MoCon::CheckSumException &e)
        {
            E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
        }
    }
    else
    {
        Nice::SeqString select = m_config->leaf(
                Basda::Mocca::MoCon::cfgDatasheetEncoderType())
                ->getAttribute<Nice::SeqString>("SELECT");
        E_THROW(::Basda::MoCon::CmdForAEncException, "Command is only for absolute encoder. No absolute encoder is configured. " << select.at(encoderType) << " is configured. Absolute encoder position is set to zero.");
//        D_LOG("Command is only for absolute encoder. " << select.at(encoderType) << " is configured. Absolute encoder position is set to zero.")
    }

    return aEncPosition;
}

int Basda::MoConModule::getIEncPosition()
{
    D_LOG("getIEncPosition of card " << m_cardNo << " module " << m_moduleNo);

    int iEncPosition = 0;
    int encoderType = 0;
    encoderType = m_config->getAtNode<int>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderType());

    // there is now way to figure out if a incremental encoder is connected to the MoCon
    // we have to trust the configuration
    // if this command is called and the configuration is not configured for a
    // incremental encoder, an exception will be thrown and the incremental encoder
    // position will be set to zero
    if (encoderType == Basda::EncoderType::INCREMENTAL_ENCODER
            || encoderType == Basda::EncoderType::INCREMENTAL_AND_ABSOLUTE_ENCODER)
    {
        try
        {
            std::string ret;

            m_protocol->get(Basda::Cmd::MOCON_GET_IENC_ACTUAL_POSITION,
                            Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                            m_cardNo, m_moduleNo, ret);
            iEncPosition = getValue<int>(ret);
            m_config->setAtNode<int>(
                    Basda::Mocca::Dev::PropertyName::incrementalEncoderPosition(),
                    iEncPosition);
        }

        catch (Basda::MoCon::CheckSumException &e)
        {
            E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
        }
    }
    else
    {
        Nice::SeqString select = m_config->leaf(
                Basda::Mocca::MoCon::cfgDatasheetEncoderType())
                ->getAttribute<Nice::SeqString>("SELECT");
        E_THROW(::Basda::MoCon::CmdForIEncException, "Command is only for incremental encoder. No incremental encoder is configured. " << select.at(encoderType) << " is configured. Incremental encoder position is set to zero.");
//        D_LOG("Command is only for incremental encoder. " << select.at(encoderType) << " is configured. Incremental encoder position is set to zero.")
    }

    return iEncPosition;
}

void Basda::MoConModule::setProfilePosition(double _position)
{
//     Nice::Guard guard (m_mutex);

    D_LOG("setProfilePosition on card " << m_cardNo << " module " << m_moduleNo << " " << _position);

// the method would throw an error in case the device init method tries to set
// a wrong position value which was received from the MoCon previously

//    if (!isnan(m_travelRange.x()) && _position <= m_travelRange.x())
//    {
//        E_THROW(::Basda::MoCon::OutOfRangeException, "Position value (" << _position << ") is less then minimum software limit (" << m_travelRange.x() << ").")
//    }
//    if (!isnan(m_travelRange.y()) && _position >= m_travelRange.y())
//    {
//        E_THROW(::Basda::MoCon::OutOfRangeException, "Position value (" << _position << ") is bigger then maximum software limit (" << m_travelRange.y() << ").")
//    }
//
    try
    {
        m_protocol->set(Basda::Cmd::MOCON_SET_PROFILE_POSITION,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, (int) _position);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

}

int Basda::MoConModule::getVelocity()
{
    D_LOG("getVelocity of card " << m_cardNo << " module " << m_moduleNo);

    int velocity = 0;
    try
    {
        std::string ret;

        m_protocol->get(Basda::Cmd::MOCON_GET_CURRENT_VELOCITY,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);

        velocity = getValue<int>(ret);
        m_config->setAtNode<int>(Basda::Mocca::Dev::PropertyName::velocity(),
                                 velocity);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    return velocity;
}

int Basda::MoConModule::getIEncVelocity()
{
    D_LOG("getIEncVelocity of card " << m_cardNo << " module " << m_moduleNo);

    int iEncVelocity = 0;
    int encoderType = 0;
    if ((encoderType = m_config->getAtNode<int>(
            Basda::Mocca::MoCon::cfgDatasheetEncoderType())) == 1)
    {
        try
        {
            std::string ret;

            m_protocol->get(Basda::Cmd::MOCON_GET_IENC_ACTUAL_VELOCITY,
                            Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                            m_cardNo, m_moduleNo, ret);
            iEncVelocity = getValue<int>(ret);
        }

        catch (Basda::MoCon::CheckSumException &e)
        {
            E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
        }
    }
    else
    {
        Nice::SeqString select = m_config->leaf(
                Basda::Mocca::MoCon::cfgDatasheetEncoderType())
                ->getAttribute<Nice::SeqString>("SELECT");
        E_THROW(::Basda::MoCon::CmdForIEncException, "Command is only for incremental encoder. A " << select.at(encoderType) << "is configured");
    }

    return iEncVelocity;
}

int Basda::MoConModule::getStartHomeDistance()
{
    D_LOG("getStartHomeDistance of card " << m_cardNo << " module " << m_moduleNo);

    int startHomeDistance = 0;
    try
    {
        std::string ret;

        m_protocol->get(Basda::Cmd::MOCON_GET_START_HOME_DISTANCE,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);
        startHomeDistance = getValue<int>(ret);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    return startHomeDistance;
}

void Basda::MoConModule::loadMotorSettings()
{
    D_LOG("loadMotorSettings on card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_LOAD_MOTOR_SETTINGS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::saveMotorSettings()
{
    D_LOG("saveMotorSettings on card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_SAVE_MOTOR_SETTINGS,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::setExternalProfileBufferSize(const unsigned int _bufferSize, const bool _extended)
{
//     Nice::Guard guard (m_mutex);

    D_LOG("setExternalProfileBufferSize on card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        m_extendedProfileParamter = _extended;
        m_bufferSize = _bufferSize;
        m_externalProfileIndexCycle = 0;

        std::stringstream str;
        str << m_bufferSize << " " << _extended;
        m_protocol->set(Basda::Cmd::MOCON_SET_EXPROFILE_BUF_LEN,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, str.str());
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

//unsigned int Basda::MoConModule::getExternalProfileSize()
//{
//    return m_profile.getExternalProfileSize();
//}

void Basda::MoConModule::setExternalProfileData(const unsigned int _index,
        const unsigned int _timeBase,
        const int _velocity,
        const int _position,
        const int _acceleration,
        const int _jerk)
{
//     Nice::Guard guard (m_mutex);

    D_LOG("setExternalProfileData on card " << m_cardNo << " module " << m_moduleNo);
//    U1_LOG(m_microsteps)
//    U1_LOG(_timeBase)
//    U1_LOG(_velocity * (double) Basda::Profile::FixPointEncoding_16_16)
//    U1_LOG(_position)
//    U1_LOG(_acceleration * (double) Basda::Profile::FixPointEncoding_16_16)
//    U1_LOG(_jerk)

    try
    {
        std::stringstream str;
        if (m_extendedProfileParamter)
            str << _index << " " << _timeBase << " " << _velocity << " "
                    << _position << " " << _acceleration << " " << _jerk;
        else
            str << _index << " " << _timeBase << " " << _velocity << " "
                    << _position;
        m_protocol->set(Basda::Cmd::MOCON_SET_EXPROFILE_DATA,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, str.str());
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::setExternalProfileStart(const Basda::ValueStartMode::Constant _startMode, const Nice::Date _startDate)
{
    D_LOG("Start external profile " << (_startMode ? " from the last index" : " from the beginning") << " at " << _startDate <<  " on card " << m_cardNo << " module " << m_moduleNo)
//     Nice::Guard guard (m_mutex);

//    if (_startDate != Nice::Date::microSeconds(-1))
//    {
//        D_LOG("setExternalProfileStart on card " << m_cardNo << " module " << m_moduleNo << " at " << _startDate);
//    }
//
    if (!m_config->getAtNode<bool>(
                    Basda::Mocca::MoCon::varActivityStatusMotorOn()))
    {
        E_LOG("Motor is off. Motion command will be ignored.")
        E_THROW(::Basda::MoCon::MotorOffException, "Motor is off. Motion command will be ignored.")
    }

    try
    {
        std::stringstream str;
        if (_startDate < Nice::Date::microSeconds(0))
        {
            U2_LOG("start external profile on card " << m_cardNo << " module " << m_moduleNo << " now.");
            str << _startMode;
            m_protocol->set(Basda::Cmd::MOCON_EXPROFILE_START,
                            Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                            m_cardNo, m_moduleNo, str.str());
        }
        else
        {
//            getCurrentTime();
            Nice::I64 startCycle = ((Nice::I64) (((_startDate - m_currentPcDate)
                    .toMicroSecondsDouble() / m_cycleTime))
                    + m_currentMoConClocks);

            U2_LOG("start external profile on card " << m_cardNo << " module " << m_moduleNo << " at " << _startDate << " (" << startCycle << ")");
            str << startCycle << " " << _startMode;
//             str << (_startTime * m_cycleTime) << " " << _startMode;
            m_protocol->set(Basda::Cmd::MOCON_EXPROFILE_TIME_START,
                            Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                            m_cardNo, m_moduleNo, str.str());
        }
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

void Basda::MoConModule::setExternalProfileStop()
{
    D_LOG("setExternalProfileStop on card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_EXPROFILE_STOP,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo);
        m_config->setAtNode<bool>( Basda::Mocca::MoCon::varMotionComplete(), true);
    }
    catch(::Basda::MoCon::NoBufferDefinedException &e)
    {
        /* to stop an undefined profile is supposedly harmless, RJM 2019-11-22
        */
        m_config->setAtNode<bool>( Basda::Mocca::MoCon::varMotionComplete(), true);
    }
    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

int Basda::MoConModule::getExternalProfileInfo()
{
    D_LOG("getExternalProfileInfo of card " << m_cardNo << " module " << m_moduleNo);

    unsigned int externalProfileInfo = 0;
    try
    {
        std::string ret;

        m_protocol->get(Basda::Cmd::MOCON_EXPROFILE_INFO,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);
        externalProfileInfo = getValue<unsigned int>(ret);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }

    // MoCon returns always the next segment
    return externalProfileInfo - 1;
}

void Basda::MoConModule::clearExternalProfileBuffer()
{
    D_LOG("setExternalProfileClearBuffer on card " << m_cardNo << " module " << m_moduleNo);

    try
    {
        m_protocol->set(Basda::Cmd::MOCON_EXPROFILE_BUF_CLEAR,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo);
        m_positionSequence.clear();
        /* while stopping the motor in external profile mode, this function is called, 
        * and waitForNextTrigger() in NDevice.cc checks with isExternalProfileDone() 
        * the m_exernalProfileBuffer.  So it may be wise to clear externalProfileBuffer too?
        * The side effect might be that some profiling might then calculate the
        * percentage of the completion as being zero, and that this function is also
        * called during the stages of initializing a new buffer and 
        * loading the software buffer (for long trajectories) in chunks into the Mocon buffer (!) RJM 2019-11-22
        // m_externalProfileBuffer.clear();
        */
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
}

Nice::Time Basda::MoConModule::initExternalProfile(int _frequency,
                                                   unsigned int _maxSamplesPerSegment,
                                                   unsigned int _minSamplesPerSegment,
                                                   unsigned int _faultTolerance)
{
    m_externalProfileBuffer.clear();

    m_frequency = _frequency;
    Nice::Time segmentLength = Nice::Time::seconds(_maxSamplesPerSegment/m_frequency);

    m_blockSize =
            Nice::Time::seconds(
                    segmentLength.toSecondsDouble()
                            * m_config->getAtNode<Nice::U32>(
                                    Basda::Mocca::MoCon::cfgDatasheetSegmentsPerBlock()));

    m_timeResolution = Nice::Time::seconds( 1.0 / m_frequency);

    m_profile.setExternalProfileFaultTolerance(_faultTolerance);
    m_profile.setExternalProfileMaxSamplesPerSegment(_maxSamplesPerSegment);
    m_profile.setExternalProfileMinSamplesPerSegment(_minSamplesPerSegment);

    m_microsteps = 1;
    if (m_config->getAtNode<int>( Basda::Mocca::MoCon::cfgDatasheetMotorType()) == Basda::MotorType::STEPPER)
        m_microsteps =
                m_config->leaf(
                        Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue())
                        ->get<Nice::U32>();

    // basic resolution in [steps / revolution]
    m_basicResolution = m_config->getAtNode<Nice::U16>(
            Basda::Mocca::MoCon::cfgDatasheetBasicResolution());
    // basic acceleration in [revolution / minute2]
    m_basicAcceleration =
            m_config->getAtNode<Nice::U32>(
                    Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration());

    // accelerationPerCycle is the basic acceleration value that is converted into
    // the MoCon units [steps / cycle2]
    // conversion equation is:
    // [steps / cycle2] = [(microseconds / cycle)2]
    //                  * [revolution / minute2]
    //                  * [steps / revolution]
    //                  * [(minute / 60 seconds)2]
    // additional this value is shifted by FixPointEncoding_16_16 (scale up)
    m_accelerationPerCycle = m_cycleTime * m_cycleTime
            * (double) Basda::Profile::FixPointEncoding_16_16
            / (1000000.0 * 1000000.0) * m_basicAcceleration * m_basicResolution
            * (double) m_microsteps / 3600.0;
    U2_LOG("load external profile parameter: ")
    U2_LOG("     m_blockSize            " << m_blockSize)
    U2_LOG("     m_timeResolution       " << m_timeResolution)
    U2_LOG("     _segmentLength         " << segmentLength)
    U2_LOG("     _maxSamplesPerSegment  " << _maxSamplesPerSegment)
    U2_LOG("     _minSamplesPerSegment  " << _minSamplesPerSegment)
    U2_LOG("     m_microsteps           " << m_microsteps)
    U2_LOG("     basicResolution        " << m_basicResolution)
    U2_LOG("     basicAcceleration      " << m_basicAcceleration)
    U2_LOG("     m_accelerationPerCycle " << m_accelerationPerCycle)
    return m_config->node(
            Basda::Mocca::MoCon::cfgConnectionUploadTime())
            ->get<Nice::Time>();
}

void Basda::MoConModule::calculateTransition(const Nice::Date &_date,
                                                  const Nice::NPoint &_positionSequence)
{
    m_startDate = _date;
    m_positionSequence = _positionSequence;
}

void Basda::MoConModule::calculateTransition(const Nice::Date &_date,
                                                  const Nice::NPoint &_positionSequence,
                                                  const Nice::Time &_transitionLength)
{
    // this procedure calculates the transit from one trajectory to another
    // it calculates a polynomial first and creates a point cloud secondly

    // backup the current trajectory to be able to reload it in case the transition is not valid
    if (m_positionSequenceBackup.empty())
        m_positionSequenceBackup = m_positionSequence; // backup position sequence
    else
       m_positionSequence = m_positionSequenceBackup; // restore position sequence when the previous transition didn't fit

    // looking for the index where the transition starts
    int transitionIndex = 0;
    while (transitionIndex < (int)m_positionSequence.size() &&
            m_startDate + Nice::Time::microSeconds((Nice::I64)(transitionIndex * 1.0 / (double)m_frequency * 1000000.0)) < (_date - _transitionLength))
    {
        transitionIndex++;
//        U6_LOG("transitionIndex " << transitionIndex << " position " << m_positionSequence[transitionIndex] << " transition start " << (m_startDate + Nice::Time::microSeconds(transitionIndex * 1.0 / (double)m_frequency * 1000000.0)))
    }

    int previousIndex = m_frequency;
    int nextIndex     = m_frequency;

    if ((transitionIndex - previousIndex) < 0)
    {
        E_LOG("Transition starts too early. Current Trajectory has to run at least " << 1.0 / m_frequency << " seconds.")
        E_THROW(Basda::MoCon::ProfileTransitionStartToEarlyException, "Transition starts too early. Current Trajectory has to run at least " << 1.0 / m_frequency << " seconds.")
    }

    //http://www.geometrictools.com/Documentation/LaplaceExpansionTheorem.pdf
    Nice::Time d0 = Nice::Time::seconds(-1); //Nice::Time::microSeconds((Nice::I64)((transitionIndex-previousIndex) * 1.0 / (double)m_frequency * 1000000.0));
    Nice::Time d1 = Nice::Time::seconds(0); //Nice::Time::microSeconds((Nice::I64)(transitionIndex * 1.0 / (double)m_frequency * 1000000.0));
    Nice::Time d2 = d1 + _transitionLength;
    Nice::Time d3 = d2 + Nice::Time::seconds(1); //Nice::Time::microSeconds((Nice::I64)(nextIndex * 1.0 / (double)m_frequency * 1000000.0));

    Nice::SeqSeqDouble m;
    {
        Nice::SeqDouble f;
        f.push_back(1);
        f.push_back(d1.toMicroSecondsDouble());
        f.push_back(d1.toMicroSecondsDouble()*d1.toMicroSecondsDouble());
        f.push_back(d1.toMicroSecondsDouble()*d1.toMicroSecondsDouble()*d1.toMicroSecondsDouble());
        m.push_back(f);
    }
    {
        Nice::SeqDouble f;
        f.push_back(1);
        f.push_back(d2.toMicroSecondsDouble());
        f.push_back(d2.toMicroSecondsDouble()*d2.toMicroSecondsDouble());
        f.push_back(d2.toMicroSecondsDouble()*d2.toMicroSecondsDouble()*d2.toMicroSecondsDouble());
        m.push_back(f);
    }
    {
        Nice::SeqDouble f;
        f.push_back(0);
        f.push_back(1);
        f.push_back(2*d1.toMicroSecondsDouble());
        f.push_back(3*(d1.toMicroSecondsDouble()*d1.toMicroSecondsDouble()));
        m.push_back(f);
    }
    {
        Nice::SeqDouble f;
        f.push_back(0);
        f.push_back(1);
        f.push_back(2*d2.toMicroSecondsDouble());
        f.push_back(3*(d2.toMicroSecondsDouble()*d2.toMicroSecondsDouble()));
        m.push_back(f);
    }

    Nice::SeqDouble y;
    y.push_back(m_positionSequence[transitionIndex]);
    y.push_back( _positionSequence[0]);

    y.push_back((m_positionSequence[transitionIndex] - m_positionSequence[transitionIndex-previousIndex]) /
                (d1.toMicroSecondsDouble() - d0.toMicroSecondsDouble()));

    y.push_back(( _positionSequence[nextIndex] - _positionSequence[0]) /
                (d3.toMicroSecondsDouble() - d2.toMicroSecondsDouble()));

    double s0 = m[0][0] * m[1][1] - m[1][0] * m[0][1];
    double s1 = m[0][0] * m[1][2] - m[1][0] * m[0][2];
    double s2 = m[0][0] * m[1][3] - m[1][0] * m[0][3];
    double s3 = m[0][1] * m[1][2] - m[1][1] * m[0][2];
    double s4 = m[0][1] * m[1][3] - m[1][1] * m[0][3];
    double s5 = m[0][2] * m[1][3] - m[1][2] * m[0][3];

    double c5 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
    double c4 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
    double c3 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
    double c2 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
    double c1 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
    double c0 = m[2][0] * m[3][1] - m[3][0] * m[2][1];

    // Should check for 0 determinant
    double det = s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0 ;

    if (det == 0)
    {
        E_LOG("Transition matrix is not invertable.")
        E_THROW(Basda::MoCon::ProfileTransitionException, "Transition matrix is not invertible.")
    }

    Nice::SeqSeqDouble mtx;
    {
        Nice::SeqDouble b;
        b.push_back(( m[1][1] * c5 - m[1][2] * c4 + m[1][3] * c3) / det);
        b.push_back((-m[0][1] * c5 + m[0][2] * c4 - m[0][3] * c3) / det);
        b.push_back(( m[3][1] * s5 - m[3][2] * s4 + m[3][3] * s3) / det);
        b.push_back((-m[2][1] * s5 + m[2][2] * s4 - m[2][3] * s3) / det);
        mtx.push_back(b);
    }
    {
        Nice::SeqDouble b;
        b.push_back((-m[1][0] * c5 + m[1][2] * c2 - m[1][3] * c1) / det);
        b.push_back(( m[0][0] * c5 - m[0][2] * c2 + m[0][3] * c1) / det);
        b.push_back((-m[3][0] * s5 + m[3][2] * s2 - m[3][3] * s1) / det);
        b.push_back(( m[2][0] * s5 - m[2][2] * s2 + m[2][3] * s1) / det);
        mtx.push_back(b);
    }
    {
        Nice::SeqDouble b;
        b.push_back(( m[1][0] * c4 - m[1][1] * c2 + m[1][3] * c0) / det);
        b.push_back((-m[0][0] * c4 + m[0][1] * c2 - m[0][3] * c0) / det);
        b.push_back(( m[3][0] * s4 - m[3][1] * s2 + m[3][3] * s0) / det);
        b.push_back((-m[2][0] * s4 + m[2][1] * s2 - m[2][3] * s0) / det);
        mtx.push_back(b);
    }
    {
        Nice::SeqDouble b;
        b.push_back((-m[1][0] * c3 + m[1][1] * c1 - m[1][2] * c0) / det);
        b.push_back(( m[0][0] * c3 - m[0][1] * c1 + m[0][2] * c0) / det);
        b.push_back((-m[3][0] * s3 + m[3][1] * s1 - m[3][2] * s0) / det);
        b.push_back(( m[2][0] * s3 - m[2][1] * s1 + m[2][2] * s0) / det);
        mtx.push_back(b);
    }

    double p = mtx[0][0] * y[0] + mtx[0][1] * y[1] + mtx[0][2] * y[2] + mtx[0][3] * y[3];
    double v = mtx[1][0] * y[0] + mtx[1][1] * y[1] + mtx[1][2] * y[2] + mtx[1][3] * y[3];
    double a = mtx[2][0] * y[0] + mtx[2][1] * y[1] + mtx[2][2] * y[2] + mtx[2][3] * y[3];
    double j = mtx[3][0] * y[0] + mtx[3][1] * y[1] + mtx[3][2] * y[2] + mtx[3][3] * y[3];

    Nice::NPoint transition;

    int i = transitionIndex;
    while (m_startDate + Nice::Time::microSeconds((Nice::I64)(i * 1.0 / (double)m_frequency * 1000000.0)) < (_date))
    {
        long double t = (Nice::Time::microSeconds((Nice::I64)((i-transitionIndex) * 1.0 / (double)m_frequency * 1000000.0))).toMicroSecondsDouble();

        transition.push_back((double)(p + v * t + a * t*t + j * t*t*t));

//U6_LOG("i " << i << " transition "<< transition[transition.size()-1])

        i++;
    }

    m_positionSequence.erase(m_positionSequence.begin() + transitionIndex,
                             m_positionSequence.end());
    m_positionSequence.insert(m_positionSequence.end(),
                              transition.begin(), transition.end());
    m_positionSequence.insert(m_positionSequence.end(),
                              _positionSequence.begin(), _positionSequence.end());
}

unsigned int Basda::MoConModule::fitTrajectory()
{
    D_LOG("fit trajectory ")
    std::vector<Nice::PointVar> trajectory;
    Nice::PointVar point;

//    m_cycleTime =
//            m_cycleTime != Nice::Time::seconds(0) ?
//                    m_cycleTime : Nice::Time::seconds(TIME_PER_CYCLE);
//    getCurrentTime();
    std::stringstream ss;

    // convert trajectory to external profile
    for (unsigned int i = 0; i < m_positionSequence.size(); i++)
    {
        point.xp = (double) lrint(i * m_timeResolution.toMicroSecondsDouble() / m_cycleTime); // point.xp in cycles
        point.yp = m_positionSequence.at(i) * m_microsteps;
        trajectory.push_back(point);
    }

    Nice::I64 startCycle = ((Nice::I64) (((m_startDate - m_currentPcDate).toMicroSecondsDouble() / m_cycleTime)) + m_currentMoConClocks);

    //    m_profile.setExternalProfilePositionSequence(trajectory);
    return m_profile.fitExternalProfile(m_startDate, startCycle, trajectory, m_cycleTime);
    // m_profile.dumpExternalProfile();
}

unsigned int Basda::MoConModule::shinsFitTrajectory()
{
    D_LOG("fit trajectory ")
    std::vector<Nice::PointVar> trajectory;
    Nice::PointVar point;

//    m_cycleTime = m_cycleTime != Nice::Time::seconds(0) ? m_cycleTime : Nice::Time::seconds(TIME_PER_CYCLE);
//    getCurrentTime();

    // convert trajectory to external profile
    U2_LOG("m_timeResolution : " << m_timeResolution << "; m_cycleTime : " << m_cycleTime << "; m_microsteps : " << m_microsteps << "; m_startDate : " << m_startDate << "; m_currentDate : " << m_currentPcDate << "; m_currentMoConClocks : " << m_currentMoConClocks);
    for (unsigned int i = 0; i < m_positionSequence.size(); i++)
    {
        point.xp = (double) lrint(i * m_timeResolution.toMicroSecondsDouble() / m_cycleTime); // point.xp in cycles
        point.yp = m_positionSequence.at(i) * m_microsteps;
        trajectory.push_back(point);
    }
    Nice::I64 startCycle = ((Nice::I64) (((m_startDate - m_currentPcDate).toMicroSecondsDouble() / m_cycleTime)) + m_currentMoConClocks);

    unsigned int num_segments = m_profile.shinsFitExternalProfile(m_startDate, startCycle, trajectory, m_cycleTime);
    return num_segments;
}

int Basda::MoConModule::shinsGetStartingRamp(const Nice::NPoint & _positionSequence, double time_interval_microseconds)
{
    std::vector<Nice::PointVar> trajectory;
    Nice::PointVar point;
    U2_LOG("_positionSequence.size() = " << _positionSequence.size() << "; time_interval_microseconds : " << time_interval_microseconds << ";m_timeResolution : " << m_timeResolution << "; m_cycleTime : " << m_cycleTime << "; m_microsteps : " << m_microsteps << "; m_startDate : " << m_startDate << "; m_currentDate : " << m_currentPcDate << "; m_currentMoConClocks : " << m_currentMoConClocks);
    for (unsigned int i = 0; i < _positionSequence.size(); i++)
    {
        point.xp = (double) lrint(i * time_interval_microseconds / m_cycleTime); // point.xp in cycles
        point.yp = _positionSequence.at(i) * m_microsteps;
        trajectory.push_back(point);
    }
    U2_LOG("_positionSequence.size() = " << _positionSequence.size());
    return m_profile.shinsGetStartingRamp(trajectory);
}



void Basda::MoConModule::validateExternalProfile()
{
    unsigned int bufferSize = m_profile.getExternalProfileSize() - 1;
    int position;
    int velocity;
    int acceleration;
    int jerk;
    int numberOfCycles;
    bool bErrors = false;
    std::vector<std::string> error_strings;
    bool bMinRange = true, bMaxRange = true, bMaxVelocity = true, bMaxAcceleration = true;

    const double encode16 = 65536.;
    const double encode32 = 65536.*65536.;

    double doublePosition, doubleVelocity, doubleAcceleration, doubleJerk;
    double doubleOldPosition, doubleOldVelocity, doubleOldAcceleration;
    double maxDeltaPosition = 0, maxDeltaVelocity = 0;
    double maxVelocity = 0, maxAcceleration = 0, maxJerk = 0;

    // basic resolution in [steps / revolution]
    Nice::U16 basicResolution = m_config->getAtNode<Nice::U16>(Basda::Mocca::MoCon::cfgDatasheetBasicResolution());
    // travel range in [steps]
    Nice::Point travelrange = m_config->getWithDefault<Nice::Point>(Basda::Mocca::Dev::PropertyName::datasheetTravelRange(), Nice::Point(DBL_MIN, DBL_MAX));
    // basic velocity in [revolution / minute]
    double basicVelocity = m_config->getAtNode<double>(Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight());
    // basic acceleration in [revolution / minute2]
    Nice::U32 basicAcceleration = m_config->getAtNode<Nice::U32>(Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration());
    // basic jerk in [revolution / minute3]
    Nice::U32 basicJerk = m_config->getAtNode<Nice::U32>(Basda::Mocca::MoCon::cfgDatasheetBasicJerk());
    // cycle time in [microseconds / cycle]
    m_cycleTime = m_cycleTime != 0.0 ? m_cycleTime : Basda::Constant::TIME_PER_CYCLE;

    // travel range in [steps]
    int travelRangeMin = (int) travelrange.xp;// * m_microsteps;
    int travelRangeMax = (int) travelrange.yp;// * m_microsteps;

    // velocityPerCycle is the basic velocity value that is converted into the MoCon units [steps / cycle]conversion equation is:
    // [steps / cycle] = [microseconds / cycle] * [revolution / minute] * [steps / revolution] * [minute / 60 seconds]
    // additional this value is shifted by FixPointEncoding_16_16 (scale up)
    double velocityPerCycle = m_cycleTime
            * (double) Basda::Profile::FixPointEncoding_16_16 / 1000000.0
            * basicVelocity * basicResolution * m_microsteps / 60.0;

    basicAcceleration = 12016;
    // accelerationPerCycle is the basic acceleration value that is converted into the MoCon units [steps / cycle2] conversion equation is:
    // [steps / cycle2] = [(microseconds / cycle)2] * [revolution / minute2] * [steps / revolution] * [(minute / 60 seconds)2]
    // additional this value is shifted by FixPointEncoding_16_16 (scale up)
    double accelerationPerCycle = m_cycleTime * m_cycleTime
            * (double) Basda::Profile::FixPointEncoding_16_16
            / (1000000.0 * 1000000.0) * basicAcceleration * basicResolution
            * m_microsteps / 3600.0;
    double cyclesPerMinute = 60000000./m_cycleTime;
    accelerationPerCycle = encode16*basicAcceleration*basicResolution*m_microsteps/(cyclesPerMinute*cyclesPerMinute);

    basicJerk = 847;
    // jerkPerCycle is the basic jerk that is converted into the MoCon units [steps / cycle3] conversion equation is:
    // [steps / cycle3] = [(microseconds / cycle)3] * [revolution / minute3] * [steps / revolution] * [(minute / 60 seconds)3]
    // additional this value is shifted by FixPointEncoding_0_32 (scale up)
    double jerkPerCycle = m_cycleTime * m_cycleTime * m_cycleTime
            * (double) Basda::Profile::FixPointEncoding_0_32
            / (1000000.0 * 1000000.0 * 1000000.0) * basicJerk * basicResolution
            * m_microsteps / 216000.0;
    jerkPerCycle = encode32*basicJerk*basicResolution*m_microsteps/(cyclesPerMinute*cyclesPerMinute*cyclesPerMinute);
    U9_LOG("Travel Range : [" << travelRangeMin << ", " << travelRangeMax << "]; velocityPerCycle : " << velocityPerCycle << "; accelerationPerCycle : " << accelerationPerCycle);

    std::string basicVelocityUnit = m_config->leaf(Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart())->getAttribute<std::string>("UNIT");
    std::string basicAccelerationUnit = m_config->leaf(Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration())->getAttribute<std::string>("UNIT");
    std::string basicJerkUnit = m_config->leaf(Basda::Mocca::MoCon::cfgDatasheetBasicJerk())->getAttribute<std::string>("UNIT");

    double position_error_multiplier = 4;
    double position_error_threshold = position_error_multiplier*350; // ~ half absolute encoder step (1 ABSENC = 625 STEPS)
    double velocity_error_threshold = accelerationPerCycle; // 4228 acceleration to reach in 1s max velocity
    U8_LOG(__FUNCTION__ << " ~ " << bufferSize << " " << numberOfCycles);
    m_profile.getExternalProfile(0, position, velocity, acceleration, jerk, numberOfCycles);
    doublePosition = position;
    doubleVelocity = velocity;
    doubleAcceleration = acceleration;
    doubleJerk = jerk;
    int current_position = getMEncPosition();
    doublePosition = current_position;
    if (abs(position - current_position) > position_error_threshold)
    {
        std::stringstream errorMsg;
        errorMsg << "Position at the beginning of external profile deviates from the current module postion above the threshold : " << position - current_position << "/" << position_error_threshold;
        bErrors = true;
        error_strings.push_back(errorMsg.str());
    }
    for (unsigned int i = 0; i < bufferSize; i++)
    {
        m_profile.getExternalProfile(i, position, velocity, acceleration, jerk, numberOfCycles);
        doubleOldVelocity = velocity;
        doubleOldAcceleration = doubleAcceleration = acceleration;
        doubleJerk = jerk;
        if(abs(position - doublePosition) > abs(maxDeltaPosition))maxDeltaPosition = position - doublePosition;
        if (abs(position - doublePosition) > position_error_threshold)
        {
            std::stringstream errorMsg;
            errorMsg << "Position at the beginning of segment "  << i << " deviates from the position at the end of previous segment above the current threshold : " << position - doublePosition << "/" << position_error_threshold;
            bErrors = true;
            error_strings.push_back(errorMsg.str());
        }
        doublePosition = position;
        doubleOldPosition = position;

        if(abs(velocity - doubleVelocity) > abs(maxDeltaVelocity))maxDeltaVelocity = velocity - doubleVelocity;
        if (abs(velocity - doubleVelocity) > velocity_error_threshold)
        {
            U7_LOG("Delta Velocity in seg " << i << " : " << velocity - doubleVelocity);
        }
        if (abs(velocity - doubleVelocity) > 4*velocity_error_threshold)
        {
            std::stringstream errorMsg;
            errorMsg << "Velocity at the beginning of segment "  << i << " deviates from the velocity at the end of previous segment above the current threshold : " << velocity - doubleVelocity << "/" << velocity_error_threshold;
            bErrors = true;
            error_strings.push_back(errorMsg.str());
        }
        doubleVelocity = velocity;
        if(abs(doubleJerk) > abs(maxJerk))maxJerk = doubleJerk;

//        velocity /= (double) FixPointEncoding_16_16;
//        acceleration /= (double) FixPointEncoding_16_16;
//        jerk /= (double) FixPointEncoding_0_32;

//        U6_LOG(i << "\t" << "\t" << position << "\t" << velocity << "\t" << acceleration << "\t" << jerk << "\t" << numberOfCycles << "\t" << bufferSize)

        // for each MoCon cycle the position, velocity and acceleration are calculated
        for (int j = 0; j < numberOfCycles + 1; j++)
        {
//             std::cout << i << " " << j << "\r" << std::flush; 
            // The position, velocity and acceleration are calculated as it would
            // happen in the MoCon.
            // Since the velocity, acceleration and jerk are stored as integer values
            // in the MoCon memory, the values are scaled up.
            // For the calculation, the values are scaled down and the new position,
            // acceleration and velocity are calculated based on double values.
            // Finally the new position, velocity and acceleration value are
            // scaled up again and saved as integer value.
            position += int(
                    (double) velocity
                            / (double) Basda::Profile::FixPointEncoding_16_16
                            + (double) acceleration
                                    / (double) Basda::Profile::FixPointEncoding_16_16
                                    / 2
                            + (double) jerk
                                    / (double) Basda::Profile::FixPointEncoding_0_32
                                    / 6);

            velocity +=
                    int((double) acceleration
                            / (double) Basda::Profile::FixPointEncoding_16_16
                            + (double) jerk
                                    / (double) Basda::Profile::FixPointEncoding_0_32
                                    / 2
                                    * (double) Basda::Profile::FixPointEncoding_16_16);

            acceleration += int(
                    (double) jerk / (double) Basda::Profile::FixPointEncoding_0_32
                            * (double) Basda::Profile::FixPointEncoding_16_16);


            doublePosition += doubleVelocity/encode16 + doubleAcceleration/(2*encode16) + doubleJerk/(6*encode32);
            doubleVelocity += doubleAcceleration + doubleJerk/(2*encode16);
            doubleAcceleration += doubleJerk/encode16;
            if(abs(doubleVelocity) > abs(maxVelocity))maxVelocity = doubleVelocity;
            if(i > 0 && i < bufferSize - 2 && abs(doubleAcceleration) > abs(maxAcceleration))maxAcceleration = doubleAcceleration;


            if (doublePosition < travelRangeMin && bMinRange)
            {
                bMinRange = false;
                std::stringstream errorMsg;
                errorMsg << "Position (in microsteps) is out of travel range. " << (int)doublePosition << " < " << travelRangeMin;
                bErrors = true;
                error_strings.push_back(errorMsg.str());
            }

            if (doublePosition > travelRangeMax && bMaxRange)
            {
                bMaxRange = false;
                std::stringstream errorMsg;
                errorMsg << "Position (in microsteps) is out of travel range. " << (int)doublePosition << " > " << travelRangeMax;
                bErrors = true;
                error_strings.push_back(errorMsg.str());
            }

            if (doubleVelocity > velocityPerCycle && bMaxVelocity)
            {
                bMaxVelocity = false;
                std::stringstream errorMsg;
                errorMsg << "Velocity is greater than the velocity defined in the config file ( " << (int)doubleVelocity << "steps/cycle > " << velocityPerCycle << "steps/cycle (" << basicVelocity << basicVelocityUnit << " )). ";
                bErrors = true;
                error_strings.push_back(errorMsg.str());
            }

            if (doubleAcceleration > accelerationPerCycle && bMaxAcceleration)
            {
                bMaxAcceleration = false;
                std::stringstream errorMsg;
                errorMsg << "Acceleration is greater than the acceleration defined in the config file ( " << (int)doubleAcceleration << "steps/cycle^2 > " << accelerationPerCycle << "steps/cycle^2 (" << basicAcceleration << basicAccelerationUnit << " )). ";
                bErrors = true;
                error_strings.push_back(errorMsg.str());
            }

        }
        /* if BASIC.JERK of the property tree is zero, ignore it and don't set a limit on the jerk parameter (RJM 2018-01-17) */
        if ( basicJerk != 0 &&  fabs(jerk) > jerkPerCycle)
        {
            std::stringstream errorMsg;
            errorMsg << "Segment " << i << " : Jerk is greater than the jerk defined in the config file ( " << jerk << "steps/cycle^3 > " << jerkPerCycle << "steps/cycle^3 (" << basicJerk << basicJerkUnit << " ). ";
            bErrors = true;
            error_strings.push_back(errorMsg.str());
        }
        int newPosition = doublePosition, newVelocity, newAcceleration, newJerk, newNumberOfCycles;
        if(i < bufferSize - 1)
        {
            m_profile.getExternalProfile(i + 1, newPosition, newVelocity, newAcceleration, newJerk, newNumberOfCycles);
        }
        U8_LOG("dbl " << i << " ~ " << (int)doubleOldPosition << " - " << (int)doublePosition << " ~ " << newPosition - doublePosition << " ~ " << (int)doubleOldVelocity << " - " << (int)doubleVelocity << " ~ " << (int)doubleOldAcceleration << " - " << (int)doubleAcceleration << " ~ " << (int)doubleJerk << " ~ " << numberOfCycles);

    }
    U9_LOG("maxVelocity : {" << (int)maxVelocity << ", " << std::setprecision(3) << 360./40960000*60*1000000.*maxVelocity/(encode16*m_cycleTime) << "[deg/min]}; maxAcceleration : " << maxAcceleration << "; maxJerk : " << maxJerk << "; maxDeltaPosition : " << maxDeltaPosition << "; maxDeltaVelocity : " << (int)maxDeltaVelocity);
    if(bErrors)
    {
        std::vector<std::string>::iterator itErr;
        for(itErr = error_strings.begin(); itErr < error_strings.end(); itErr++)
        {
            E_LOG(*itErr);
        }
        E_THROW(Basda::MoCon::InvalidProfileException, "Found problems in current external profile");
    }
}

unsigned int Basda::MoConModule::bufferExternalProfile()
{
    Nice::Monitor::Lock lock(m_monitor);

    std::vector<Basda::MoConModuleProfile::Segment> profile = m_profile.getExternalProfile();

#if 0
    {
    std::stringstream ss;
    for (unsigned int i = 0; i < profile.size(); i++)
    {
       ss << "[" << i << ": "
       << profile.at(i).startDate << " "
       << profile.at(i).startCycle << " "
//       << profile.at(i).numberOfCycles << " "
//       << profile.at(i).velocity << " "
       << ((double)profile.at(i).position / (double)m_microsteps) << " "
//       << profile.at(i).acceleration << " "
//       << profile.at(i).jerk
       << "], ";
    }
    U4_LOG(ss.str())
    }
#endif
    if (m_externalProfileBuffer.empty()) // buffer profile
    {
        m_externalProfileBuffer = profile;
        m_externalProfileBufferSize = (unsigned int) m_externalProfileBuffer.size() + 1;
    }
    else // insert new profile
    {
//        int i = 0;
//        while (i < (int)m_externalProfileBuffer.size() && m_externalProfileBuffer[i].startCycle < profile[m_externalProfileIndexCycle].startCycle)
//            i++;

#if 0
        {
        std::stringstream ss;
        for (unsigned int i = 0; i < m_externalProfileBuffer.size(); i++)
        {
           ss << "[" << i << ": "
           << m_externalProfileBuffer.at(i).startDate << " "
           << m_externalProfileBuffer.at(i).startCycle << " "
    //       << m_externalProfileBuffer.at(i).numberOfCycles << " "
    //       << m_externalProfileBuffer.at(i).velocity << " "
           << ((double)m_externalProfileBuffer.at(i).position / (double)m_microsteps) << " "
    //       << m_externalProfileBuffer.at(i).acceleration << " "
    //       << m_externalProfileBuffer.at(i).jerk
           << "], ";
        }
        U4_LOG(ss.str())
        }
#endif

//        m_externalProfileBuffer.erase(m_externalProfileBuffer.begin() + m_externalProfileIndexCycle,
//                                      m_externalProfileBuffer.end());
        m_externalProfileBuffer.clear();
        m_externalProfileBuffer.insert(m_externalProfileBuffer.begin(),
                                       profile.begin() + m_externalProfileIndexCycle, profile.end());
        m_externalProfileBufferSize = (unsigned int) profile.size() + 1;
#if 0
        {
        std::stringstream ss;
        for (unsigned int i = 0; i < m_externalProfileBuffer.size(); i++)
        {
           ss << "[" << i << ": "
           << m_externalProfileBuffer.at(i).startDate << " "
           << m_externalProfileBuffer.at(i).startCycle << " "
    //       << m_externalProfileBuffer.at(i).numberOfCycles << " "
    //       << m_externalProfileBuffer.at(i).velocity << " "
           << ((double)m_externalProfileBuffer.at(i).position / (double)m_microsteps) << " "
    //       << m_externalProfileBuffer.at(i).acceleration << " "
    //       << m_externalProfileBuffer.at(i).jerk
           << "], ";
        }
    U4_LOG(ss.str())
        }
#endif
    }

    m_externalProfileCycles = 0;
    std::vector<Basda::MoConModuleProfile::Segment>::const_iterator itSeg;
    for(itSeg = profile.begin(); itSeg != profile.end(); itSeg++)
    {
        m_externalProfileCycles += itSeg->numberOfCycles;
    }

    m_positionSequenceBackup.clear(); // changes were taken over. This backup is now out-dated.

    return m_externalProfileBufferSize;
}

Nice::Date Basda::MoConModule::uploadExternalProfile()
{
    D_LOG("Upload external profile.")
    Nice::Monitor::Lock lock(m_monitor);

    Nice::Date startDate;  // the start date is set to 01.01.1970 00:00
//    double startCycle;
    unsigned int i = 0;
    unsigned int startSegmentOfNextBlock = i;

    int cycle = 0;  // MoCon cycle

    // in case the external profile is done, the start date 01.01.1970 00:00
    // is returned
    if (!m_externalProfileBuffer.empty())
    {
        Nice::Date blockEndDate = m_externalProfileBuffer.at(0).startDate + m_blockSize;

#if 0
        // the complete block will be uploaded
        // if the last block is smaller than the block size, everything will be
        // uploaded and the while loop ends
        {
        std::stringstream ss;
        for (unsigned int j = 0; j < m_externalProfileBuffer.size(); j++)
        {
           ss << "[" << j << ": "
           << m_externalProfileBuffer.at(j).startDate << " "
           << m_externalProfileBuffer.at(j).startCycle << " "
           << m_externalProfileBuffer.at(j).numberOfCycles << " "
           << m_externalProfileBuffer.at(j).velocity << " "
           << m_externalProfileBuffer.at(j).position << " "
           << ((double)m_externalProfileBuffer.at(j).position / (double)m_microsteps) << " "
           << m_externalProfileBuffer.at(j).acceleration << " "
           << m_externalProfileBuffer.at(j).jerk
           << "], ";
        }
        U4_LOG(ss.str())
        }
#endif
        while ((i < m_externalProfileBuffer.size())
                && (m_externalProfileBuffer.at(i).startDate < blockEndDate))
        {
            U2_LOG(m_externalProfileIndexCycle % m_bufferSize << " numberOfCycles:" 
		<< m_externalProfileBuffer.at(i).numberOfCycles << " velocity:" 
		<< m_externalProfileBuffer.at(i).velocity << " position:" 
		<< m_externalProfileBuffer.at(i).position << " acceleration:" 
		<< m_externalProfileBuffer.at(i).acceleration << " jerk:" << m_externalProfileBuffer.at(i).jerk 
		<< "; startCycle:" << m_externalProfileBuffer.at(i).startCycle << " - startDate:" << m_externalProfileBuffer.at(i).startDate)
            setExternalProfileData(m_externalProfileIndexCycle++ % m_bufferSize,
                                   m_externalProfileBuffer.at(i).numberOfCycles,
                                   m_externalProfileBuffer.at(i).velocity,
                                   m_externalProfileBuffer.at(i).position,
                                   m_externalProfileBuffer.at(i).acceleration,
                                   m_externalProfileBuffer.at(i).jerk);

            cycle += m_externalProfileBuffer.at(i).numberOfCycles;
            i++;
        }

        // exist a segment after the already uploaded block
        // the start date of this segment will be returned
        if (i < m_externalProfileBuffer.size() - 1)
            startSegmentOfNextBlock = i;
        else if (!m_externalProfileBuffer.empty())
        {
            startSegmentOfNextBlock = (unsigned int) m_externalProfileBuffer.size() - 1;
//            m_externalProfileIndexCycle--;
        }

        int externalProfileIndexCycle = m_externalProfileIndexCycle;
        if (!m_externalProfileBuffer.empty())
        {
            // Termination Segments (LN-MPIA-DES-AO-001)
            // The two termination segments at the end of each block consist of
            // a deceleration segment and the actual motion profile termination
            // segment:
            // segment position                    velocity acceleration jerk cycles
            // 1       x_end                       v_end    -a_max       0    v_end/a_max
            // 2       x_end+v_end*v_end/(2*a_max) 0        0            0    0
            int cyclesDeceleration = (int) fabs(m_externalProfileBuffer.at(startSegmentOfNextBlock).velocity / m_accelerationPerCycle);
            if (cyclesDeceleration > 0)
            {
                // in case we moving forward (in positive direction) the deceleration
                // has to be negative
                // in case we moving backward (in negative direction) the deceleration
                // has to be positive
                int accelerationPerCycle =
                        m_externalProfileBuffer.at(startSegmentOfNextBlock).velocity < 0 ?
                                (int) m_accelerationPerCycle :
                                -(int) m_accelerationPerCycle;

                // termination segment 1
                U2_LOG(m_externalProfileIndexCycle % m_bufferSize << " numberOfCycles:" 
			<< cyclesDeceleration << " velocity:" << m_externalProfileBuffer.at(startSegmentOfNextBlock).velocity 
			<< " position:" << m_externalProfileBuffer.at(startSegmentOfNextBlock).position 
			<< " acceleration:" << accelerationPerCycle << " jerk:" << 0 << "; startCycle:" 
			<< m_externalProfileBuffer.at(startSegmentOfNextBlock).startCycle << " - startDate:" << m_externalProfileBuffer.at(startSegmentOfNextBlock).startDate)
                setExternalProfileData(
                        m_externalProfileIndexCycle % m_bufferSize,
                        cyclesDeceleration,
                        m_externalProfileBuffer.at(startSegmentOfNextBlock).velocity,
                        m_externalProfileBuffer.at(startSegmentOfNextBlock).position,
                        accelerationPerCycle, 0);
                externalProfileIndexCycle++;
            }
            // termination segment 2
            int position = int(m_externalProfileBuffer.at(startSegmentOfNextBlock).position
                    - (m_externalProfileBuffer.at(startSegmentOfNextBlock).velocity
                            * m_externalProfileBuffer.at(startSegmentOfNextBlock).velocity
                            / Basda::Profile::FixPointEncoding_16_16
                            / (2 * m_accelerationPerCycle)));
            U2_LOG((externalProfileIndexCycle) % m_bufferSize << " numberOfCycles:" 
		<< 0 << " velocity:" << 0 << " position:" << position << " acceleration:" 
		<< 0 << " jerk:" << 0 << "; startCycle:" 
		<< m_externalProfileBuffer.at(startSegmentOfNextBlock).startCycle << " - startDate:" << m_externalProfileBuffer.at(startSegmentOfNextBlock).startDate)
            setExternalProfileData((externalProfileIndexCycle) % m_bufferSize,
                                   0, 0, position, 0, 0);
            startDate = m_externalProfileBuffer.at(startSegmentOfNextBlock - 1)
                    .startDate;
//            startCycle = m_externalProfileBuffer.at(m_externalProfileBuffer.size() - 1).startCycle;
        }

        m_externalProfileBuffer.erase(m_externalProfileBuffer.begin(), m_externalProfileBuffer.begin() + i);
    }
    if (startDate.toMicroSeconds() > 0)
    {
        D_LOG("Uploaded block ends at " << startDate)
    }
    else
    {
        D_LOG("trajectory done. waiting for completion event.")
    }
    return startDate; // m_externalProfileBuffer.at(0).startDate + m_cycleTime * startCycle;
}


Nice::Date Basda::MoConModule::shinsUploadExternalProfile()
{
    D_LOG("Upload external profile.")
    Nice::Monitor::Lock lock(m_monitor);

    Nice::Date startDate;  // the start date is set to 01.01.1970 00:00
    unsigned int block_index = 0;

    int cycle = 0;  // MoCon cycle

    // in case the external profile is done, the start date 01.01.1970 00:00 is returned
    if (!m_externalProfileBuffer.empty())
    {
        Nice::Date blockEndDate = m_externalProfileBuffer.at(0).startDate + m_blockSize - Nice::Time::milliSeconds(5);

        int startingSize = m_externalProfileBufferSize - 1;
        // block_index starts from 0 because m_externaleProfileBuffer previous block has been erased
        while((block_index < m_externalProfileBuffer.size() && m_externalProfileBuffer.at(block_index).startDate < blockEndDate) || (block_index == (m_externalProfileBuffer.size() - 2) || block_index == (m_externalProfileBuffer.size() - 1)))
        {
            MoConModuleProfile::Segment cur_seg = m_externalProfileBuffer.at(block_index);
            U2_LOG(m_externalProfileIndexCycle  << "/" << startingSize << "; numberOfCycles:" << cur_seg.numberOfCycles << "; velocity:" << cur_seg.velocity << "; position:" << cur_seg.position
                   << "; acceleration:" << cur_seg.acceleration << "; jerk:" << cur_seg.jerk << "; startCycle:" << cur_seg.startCycle << " - startDate:" << cur_seg.startDate);

            setExternalProfileData(m_externalProfileIndexCycle % m_bufferSize,
                                   cur_seg.numberOfCycles,
                                   cur_seg.velocity,
                                   cur_seg.position,
                                   cur_seg.acceleration,
                                   cur_seg.jerk);

            m_externalProfileIndexCycle++;
            cycle += m_externalProfileBuffer.at(block_index).numberOfCycles;
            block_index++;
        }

        if(block_index < m_externalProfileBuffer.size() - 2)
        {
            MoConModuleProfile::Segment dec_seg, stop_seg, lastSegment = m_externalProfileBuffer.at(block_index - 1);
            bool result = MoConModuleProfile::shinsGetEndingRampSegments(lastSegment, dec_seg, stop_seg);
            if(result)
            {
                dec_seg.startDate = lastSegment.startDate + Nice::Time::microSeconds(m_cycleTime*lastSegment.numberOfCycles);
                stop_seg.startDate = dec_seg.startDate + Nice::Time::microSeconds(m_cycleTime*dec_seg.numberOfCycles);
                U2_LOG(m_externalProfileIndexCycle  << "/" << startingSize << "; numberOfCycles:" << dec_seg.numberOfCycles << "; velocity:" << dec_seg.velocity << "; position:" << dec_seg.position
                    << "; acceleration:" << dec_seg.acceleration << "; jerk:" << dec_seg.jerk << "; startCycle:" << dec_seg.startCycle << " - startDate:" << dec_seg.startDate);
                setExternalProfileData((m_externalProfileIndexCycle + 0) % m_bufferSize,
                                       dec_seg.numberOfCycles,
                                       dec_seg.velocity,
                                       dec_seg.position,
                                       dec_seg.acceleration,
                                       dec_seg.jerk);
            }
            else
            {
                stop_seg.startDate = lastSegment.startDate + Nice::Time::microSeconds(m_cycleTime*lastSegment.numberOfCycles);
            }

            U2_LOG(m_externalProfileIndexCycle  << "/" << startingSize << "; numberOfCycles:" << stop_seg.numberOfCycles << "; velocity:" << stop_seg.velocity << "; position:" << stop_seg.position
                << "; acceleration:" << stop_seg.acceleration << "; jerk:" << stop_seg.jerk << "; startCycle:" << stop_seg.startCycle << " - startDate:" << stop_seg.startDate);
            setExternalProfileData((m_externalProfileIndexCycle + 1) % m_bufferSize,
                                   stop_seg.numberOfCycles,
                                   stop_seg.velocity,
                                   stop_seg.position,
                                   stop_seg.acceleration,
                                   stop_seg.jerk);
        }

        // exist a segment after the already uploaded block the start date of this segment will be returned
        if(block_index < m_externalProfileBuffer.size())
        {
            startDate = m_externalProfileBuffer.at(block_index).startDate;
        }

        m_externalProfileBuffer.erase(m_externalProfileBuffer.begin(), m_externalProfileBuffer.begin() + block_index);
    }

    return startDate;
}


void Basda::MoConModule::uploadExternalProfile(const Nice::SeqSeqInt &_segments)
{
//U4_LOG(_segments)
    for (unsigned int i = 0; i < _segments.size(); i++)
    {
//U4_LOG("index: "    << i <<
//       " time "     << _segments.at(i).at(Index::NUMBER_OF_CYCLES) <<
//       " velocity " << _segments.at(i).at(Index::VELOCITY) <<
//       " position " << _segments.at(i).at(Index::POSITION) <<
//       " acc "      << _segments.at(i).at(Index::ACCELERATION) <<
//       " jerk "     << _segments.at(i).at(Index::JERK));

        setExternalProfileData(
                i,                      //index
                _segments.at(i).at(Index::NUMBER_OF_CYCLES), //time
                _segments.at(i).at(Index::VELOCITY),  //velocity
                _segments.at(i).at(Index::POSITION),  //position
                _segments.at(i).at(Index::ACCELERATION), //acceleration
                _segments.at(i).at(Index::JERK)); //jerk
    }
}

void Basda::MoConModule::waitForEvent()
{
    Nice::Time time = m_config->getWithDefault<Nice::Time>(
            Basda::Mocca::MoCon::cfgConnectionEventTimeout(),
            Nice::Time::milliSeconds(500));

    D_LOG("waitForEvent on card " << m_cardNo << " module " << m_moduleNo << " max: " << time << " h");
    m_protocol->waitForEvent(time);
}

bool Basda::MoConModule::isExternalProfileDone()
{
    return m_externalProfileBuffer.empty();
}


unsigned int Basda::MoConModule::ExternalProfileCompletion()
{
    static bool firstTime = true;
    if(firstTime)
    {
        firstTime = false;
        U9_LOG("m_currentPcDate = " << m_currentPcDate << "; m_startDate = " << m_startDate << "; m_cycleTime = " << m_cycleTime << "; m_externalProfileCycles = " << m_externalProfileCycles);
    }
    unsigned int result = ((Nice::Date::now() - m_startDate).toMicroSecondsDouble()*100/m_cycleTime)/m_externalProfileCycles;
    return result;
}

void Basda::MoConModule::travelRangeChanged(const Nice::Point &_p)
{
    if (!isnan(_p.x()) && !isnan(_p.y()))
    {
        if (_p.x() >= _p.y())
        {
            E_THROW(Basda::MoCon::TraveRangeException, "Travel range minimum value "
            "is bigger/equal than the maximum value. Correct your configuration file!")
        }
    }

    m_travelRange = _p;
}

Nice::I64 Basda::MoConModule::getReferenceTime()
{
    Nice::Date pcDate1;
    Nice::Date pcDate2;
    Nice::I64 moConClocksReference = 0;
    Nice::Date pcDateReference;
    try
    {
        std::string ret;
        pcDate1 = Nice::Date::now();
        m_protocol->get(Basda::Cmd::MOCON_GET_MC_TIME,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);
        pcDate2 = Nice::Date::now();
        moConClocksReference = getValue<unsigned int>(ret);
        pcDateReference = pcDate1 + (pcDate2 - pcDate1) / 2;
        m_config->setAtNode<Nice::I64>(
                Basda::Mocca::MoCon::varTimeReferenceMoCon(),
                moConClocksReference);
        m_config->setAtNode<Nice::Date>(
                Basda::Mocca::MoCon::varTimeReferenceServer(),
                pcDateReference);
        m_config->setAtNode<Nice::I64>(
                Basda::Mocca::MoCon::varTimeCurrentMoCon(),
                moConClocksReference);
        m_config->setAtNode<Nice::Date>(
                Basda::Mocca::MoCon::varTimeCurrentServer(),
                pcDateReference);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
    return moConClocksReference;
}

Nice::I64 Basda::MoConModule::getCurrentTime()
{
//    U6_LOG(__FUNCTION__);
    Nice::Date pcDate1;
    Nice::Date pcDate2;

    try
    {
        std::string ret;
//        double cycleTime = m_config->getWithDefault<double>(
//                Basda::Mocca::MoCon::cfgDatasheetTimePerCycle(),
//                TIME_PER_CYCLE);
//        usleep(cycleTime * 1000000);

        pcDate1 = Nice::Date::now();
        m_protocol->get(Basda::Cmd::MOCON_GET_MC_TIME,
                        Basda::SelectMessageMode::MPIA_SELECT_NOT_EXIST,
                        m_cardNo, m_moduleNo, ret);
        pcDate2 = Nice::Date::now();
        m_currentMoConClocks = getValue<unsigned int>(ret);
        /* measure round-trip time for the query and adjust the nominal value
        * by assuming that this needs half of this time to reach the mocon
        */
        m_currentPcDate = pcDate1 + (pcDate2 - pcDate1) / 2;
        m_config->setAtNode<Nice::I64>(
                Basda::Mocca::MoCon::varTimeCurrentMoCon(),
                m_currentMoConClocks);
        m_config->setAtNode<Nice::Date>(
                Basda::Mocca::MoCon::varTimeCurrentServer(),
                m_currentPcDate);
//        m_cycleTime =
//                Nice::Time::seconds(
//                        (m_currentPcDate.toMicroSecondsDouble()
//                                - m_config->getAtNode<Nice::Date>(
//                                        Basda::Mocca::MoCon::timeReferenceServer())
//                                        .toMicroSecondsDouble())
//                                / ((double) m_currentMoConClocks
//                                        - (double) m_config
//                                                ->getAtNode<Nice::I64>(
//                                                Basda::Mocca::MoCon::timeReferenceMoCon()))
//                                / 1000000.0); // in seconds
        // the cycle time is constant
        m_cycleTime = Basda::Constant::TIME_PER_CYCLE;
//                (m_currentPcDate
//                        - m_config->getAtNode<Nice::Date>(
//                                Basda::Mocca::MoCon::timeReferenceServer()))
//                        .toMicroSecondsDouble()
//                        / ((double) m_currentMoConClocks
//                                - (double) m_config->getAtNode<Nice::I64>(
//                                        Basda::Mocca::MoCon::timeReferenceMoCon()));
        m_config->setAtNode<double>(
                Basda::Mocca::MoCon::varTimeCycle(), m_cycleTime);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        E_THROW(::Basda::MoCon::CheckSumException, e, "Motor Controller Error Number: " << getMotorControllerErrorNr());
    }
    return m_currentMoConClocks;
}

#if 0
 void
 Basda::MoConModule::setTimeBasedTraceSampleRate(const unsigned int _sampleRate)
 {
 //     Nice::Guard guard (m_mutex);

     D_LOG("setTraceSampleRate on card " << m_cardNo << " module " << m_moduleNo);

     try
     {
         m_moConModuleEvent->setTraceSampleRate(_sampleRate);
     }

     catch (Basda::MoCon::CheckSumException &e)
     {
         E_LOG(e);
         getMotorControllerErrorNr();
     }
 }

 void
 Basda::MoConModule::setTimeBasedTraceType(const unsigned int _buffer, const Basda::ValueTraceType _type)
 {
 //     Nice::Guard guard (m_mutex);

     D_LOG("setTraceType on card " << m_cardNo << " module " << m_moduleNo);

     try
     {
         std::stringstream str;
         str << _buffer << " " << _type;
         m_protocol->set(MOCON_SET_TRACE_VAR, MPIA_SELECT_NOT_EXIST, m_cardNo, m_moduleNo, str.str());
     }

     catch (Basda::MoCon::CheckSumException &e)
     {
         E_LOG(e);
         getMotorControllerErrorNr();
     }
 }

/*
 * Hallo Frank,
 nur zur Info, es hat sich was bei der Trace Ausgabe geändert.
 Jetzt kommen die Daten nicht mehr als DATA_MSG sondern als EVENT_MSG
 Beispiel ausgabe der Chipset Time
 ALT:
 1 204 1 2 1 15 1000123
 1 204 1 2 2 15 1001123
 1 204 1 2 3 15 1002123
 1 204 1 2 4 15 1003123
 1 204 1 2 5 15 1004123

 NEU:
 1 204 1 3 5 1 15 1000123
 1 204 1 3 5 2 15 1001123
 1 204 1 3 5 3 15 1002123
 1 204 1 3 5 4 15 1003123
 1 204 1 3 5 5 15 1004123

 Schönen Urlaub
 LG
 Lars
 */
 void
 Basda::MoConModule::getTimeBasedTraceData(const unsigned int _numberOfSamples, const int _numberOfLines)
 {
 //     Nice::Guard guard (m_mutex);

     D_LOG("getTraceData of card " << m_cardNo << " module " << m_moduleNo);

     try
     {
         std::string ret;
         std::stringstream parameter(std::string(""));

         if (_numberOfSamples > 0)
             parameter << _numberOfSamples;

         m_protocol->get(MOCON_GET_TRACE_DATA, MPIA_SELECT_NOT_EXIST, m_cardNo, m_moduleNo, ret, parameter.str(), _numberOfLines);

         m_moConModuleEvent->setTimeStampNow();

         std::stringstream ss(ret);
         m_moConModuleEvent->parseTraceData(ss);
     }

     catch (Basda::MoCon::CheckSumException &e)
     {
         E_LOG(e);
         getMotorControllerErrorNr();
     }
 }
 void
 Basda::MoConModule::receiveTimeBasedTraceData(const unsigned int _numberOfLines)
 {
 //     Nice::Guard guard (m_mutex);

     D_LOG("receiveTraceData of card " << m_cardNo << " module " << m_moduleNo);

     std::string ret;

     m_protocol->receiveData(MOCON_GET_TRACE_DATA, m_cardNo, m_moduleNo, ret, _numberOfLines);

     std::stringstream ss(ret);
     m_moConModuleEvent->parseTraceData(ss);
 }
 void
 Basda::MoConModule::setEventBasedTraceType(const unsigned int _buffer, const Basda::ValueTraceType _type, const unsigned int _timeBase)
 {
 //     Nice::Guard guard (m_mutex);

     D_LOG("setEventTraceType on card " << m_cardNo << " module " << m_moduleNo);

     try
     {
         std::stringstream str;
         str << _buffer << " " << _type << " " << _timeBase;
         m_protocol->set(MOCON_SET_EVENT_TRACE_VAR, MPIA_SELECT_NOT_EXIST, m_cardNo, m_moduleNo, str.str());

 //     m_moConModuleEvent->setTimeBase(_type, _timeBase);
         m_moConModuleEvent->setTimeStampNow();
     }

     catch (Basda::MoCon::CheckSumException &e)
     {
         E_LOG(e);
         getMotorControllerErrorNr();
     }

 }
 void
 Basda::MoConModule::unitChanged(const Nice::Any &_a)
 {
     //save the new unit in a member variable in order to know the "old" unit after a new unit was choosen
     m_currentUnit = m_config->node( "VAR.UNIT" )->get<int>();
     getPosition();
 }

 double
 Basda::MoConModule::convertUnit(double _position)
 {
     //first converts the position value from the previous unit into steps
     //than convert it to the target unit stored in the VAR.UNIT property
     _position = convertToLength ( convertToSteps( _position, (Unit)m_currentUnit ), (Unit)m_config->node( "VAR.UNIT" )->get<int>() );

     return _position;
 }
#endif /* 0 */
