/* $Header: https://svn.mpia.de/gulli/TwiceAsNice/branch/unstable/TwiceAsNice/basda-mocca/src/device/mpia/mocon/NDevice.cc 16132 2019-11-28 16:02:41Z mathar $
*/

#include <core/Protocol.h>
#include <core/CommandIDs.h>
#include <mocon/ChatLineMock.h>
#include <mocon/NDevice.h>
#include <mocon/Card.h>
#include <mocon/Module.h>
#include <mocon/ConfigIDs.h>
#include <Basda/DeviceFactory.h>
#include <Basda/Mocca/Constant.h>

#include <Nice/Property/BitSet.h>
#include <Nice/Map/Helper.h>
#include <Basda/Mocca/MPIA/PropertyName.h>
#include <Basda/Mocca/PropertyName.h>

#undef LOG_NAME
#define LOG_NAME name()

DEVICE_CREATE(Basda::MoConNDevice);

Basda::MoConNDevice::MoConNDevice(const Nice::JointPtr &_config) :
        Basda::MoccaNDevice(_config)
{
    addProperties();
    createInstances();
    Nice::Application::distribute(m_config);
}

Basda::MoConNDevice::~MoConNDevice()
{
    T_LOG("destroy instance")
    m_card.clear();
    m_module.clear();
    m_protocol.clear();
}

void Basda::MoConNDevice::setChatType(std::map<std::string, Nice::ChatLinePtr> _chat)
{
    m_chat = _chat;
    Nice::JointPtrMap children = m_config->node("MOD")->children();
    std::map<std::string, Nice::JointPtr>::iterator children_it =
            children.begin();

    while (children_it != children.end())
    {
        std::string address =
                (children_it->second)->getAtNode<std::string>(
                        Basda::Mocca::MoCon::cfgConnectionAddress());
        (m_protocol[address])->setChatType(m_chat[address]);
        children_it++;
    }
}

std::string Basda::MoConNDevice::createConnectionID(const std::string &_address,
        const unsigned int _cardNo,
        const unsigned int _moduleNo)
{
    std::stringstream connectionID;
    connectionID << _address << ":" << _cardNo << ":" << _moduleNo;
    return connectionID.str();
}

void Basda::MoConNDevice::createInstances()
{
    Nice::JointPtrMap children = m_config->node("MOD")->children();
    std::map<std::string, Nice::JointPtr>::iterator children_it =
            children.begin();

    std::map<std::string, MPIACoreProtocolPtr>::iterator protocol_it =
            m_protocol.begin();
    std::map<std::string, MoConCardPtr>::iterator card_it = m_card.begin();
    std::map<std::string, MoConModulePtr>::iterator module_it =
            m_module.begin();

    Nice::Guard guard(m_mutex);

    bool warning = true;
    m_isReachable = false;
    m_externalProfileSize = 0;
//    m_startMode = Basda::MOCON_MODE_START_FROM_BEGINNING;
    m_extended = 1;

    // for each motor reserve the module object and register at the card object
    while (children_it != children.end())
    {
//        D_LOG("create instance " << children_it->first)

        std::string address =
                (children_it->second)->getWithDefault<std::string>(
                        Basda::Mocca::MoCon::cfgConnectionAddress(),
                        "tcp://192.168.1.1:4000", warning);
        int cardNo = (children_it->second)->getWithDefault<int>(
                Basda::Mocca::MoCon::cfgConnectionCard(), MOCON, warning);
        int moduleNo = (children_it->second)->getWithDefault<int>(
                Basda::Mocca::MoCon::cfgConnectionModule(), 1, warning);

        m_chat[address] = (new Nice::ChatLine());

        m_config->getWithDefault<bool>(
                Basda::Mocca::Dev::PropertyName::isReachable(), m_isReachable);

        MPIACoreProtocolPtr protocol;

        // open a connection if still no connection exist with that ip address
        if ((protocol_it = m_protocol.find(address)) == m_protocol.end())
        {
            D_LOG("create instance for " << address)
            protocol = new MPIACoreProtocol(
                    m_name + "." + address,
                    MOCON_CONTROLLER_NAME,
                    MOCON_COS_VERSION_NUMBER,
                    MOCON_CONTROLLER_VERSION_NUMBER,
                    m_config->node(
                            std::string("MOD.") + children_it->first),
                            m_chat[address]);

            m_protocol.insert(std::make_pair(address, protocol));
        }
        else
        {
//            D_LOG("instance " << address << " already exist")
            protocol = protocol_it->second;
        }

        MoConCardPtr card;
        // create card object if this card object doesn't exist
        std::string connectionID = createConnectionID(address, cardNo, 0);
        if ((card_it = m_card.find(connectionID)) == m_card.end())
        {
//            D_LOG("create instance of card " << connectionID);
            card = new MoConCard(
                    m_name + "." + connectionID,
                    m_config->node(std::string("MOD.") + children_it->first),
                    protocol);
            m_card.insert(std::make_pair(connectionID, card));
        }
        else
        {
//            D_LOG("instance card " << connectionID << " already exist")
        }

        MoConModulePtr module;

        connectionID = createConnectionID(address, cardNo, moduleNo);
        if ((module_it = m_module.find(connectionID)) == m_module.end())
        {
//            D_LOG("create instance of module " << connectionID );
            module = new MoConModule(
                    m_name + "." + children_it->first,
                    m_config->node(std::string("MOD.") + children_it->first),
                    protocol);
            m_module.insert(std::make_pair(connectionID, module));
        }
        else
        {
//            D_LOG("instance " << connectionID << " already exist")
        }
        children_it++;
    }

    if (m_module.empty())
    {
        std::string errorMsg = "Could not create instance " + m_config->name()
                + ".";
        F_THROW(::Basda::Dev::OpenException, errorMsg);
    }
} /* createInstances */

void Basda::MoConNDevice::open()
{
    D_LOG("open device " << m_config->name() << ".");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::OPEN);
    m_completion.start(Basda::Command::Action::OPEN);

    std::map<std::string, MPIACoreProtocolPtr>::iterator protocol_it =
            m_protocol.begin();
    std::map<std::string, MoConModulePtr>::iterator module_it =
            m_module.begin();

    while (protocol_it != m_protocol.end())
    {
        try
        {
            (protocol_it->second)->open();
            protocol_it++;
        }

        catch (Basda::MPIACoreException &e)
        {
            std::string errorMsg = "Can't open device " + m_config->name()
                    + ".";
            m_completion.setError(errorMsg, e);
            E_THROW( ::Basda::Dev::OpenException, e, errorMsg);
        }
    }

    while (module_it != m_module.end())
    {
        (module_it->second)->open();
        module_it++;
    }

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
} /* open */

void Basda::MoConNDevice::close()
{
    D_LOG("close device " << m_config->name() << ".");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::CLOSE);
    m_completion.start(Basda::Command::Action::CLOSE);

    setIsReachable(false);
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    std::map<std::string, MoConCardPtr>::iterator jt = m_card.begin();
    std::map<std::string, MPIACoreProtocolPtr>::iterator kt =
            m_protocol.begin();

    while (module_it != m_module.end())
    {
        try
        {
            (module_it->second)->close();
        }

        catch (::Basda::MPIA::ModuleNotReservedException &e)
        {
        }

        catch (::Nice::ChatException &e)
        {
        }

        D_LOG("module freed " << module_it->first);
        module_it++;
    }

    while (jt != m_card.end())
    {
        try
        {
            (jt->second)->unlockCard();
        }

        catch (::Basda::MPIA::ModuleNotReservedException &e)
        {
        }

        catch (::Nice::ChatException &e)
        {
        }

        D_LOG("card freed " << jt->first);
        jt++;
    }

    while (kt != m_protocol.end())
    {
        try
        {
            (kt->second)->close();
        }

        catch (::Nice::ChatException &e)
        {
        }

        D_LOG("connection closed " << kt->first);
        kt++;
    }

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
} /* close */

void Basda::MoConNDevice::reset(Basda::DeviceAsync &_async)
{
    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::RESET);
    m_completion.start(Basda::Command::Action::RESET);
    deactivate(_async);
    deinit(_async);
    init(_async);
    activate(_async);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
} /* reset */

void Basda::MoConNDevice::version()
{
    std::string errorMsg = "Method not implemented";
    W_LOG(errorMsg);
} /* version */

void Basda::MoConNDevice::init(Basda::DeviceAsync &_async)
{
    D_LOG("Initialize device " << m_config->name() << ".");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::INIT);
    m_completion.start(Basda::Command::Action::INIT);

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    try
    {
        Nice::NPoint positionDev = m_config->getAtNode<Nice::NPointVar>(
                Basda::Mocca::MoCon::varMoconEncoderPosition());
        unsigned int i = 0;
        while (module_it != m_module.end())
        {
//            D_LOG("initialize module " << module_it->first)
            D_LOG("set reference time " << module_it->first)
            // motor init needs only be done when a new setting is uploaded
//            (module_it->second)->initializeMotor();
            (module_it->second)->getReferenceTime();

            if ((i < positionDev.size()) && (positionDev[i] != 0.0))
                (module_it->second)->setProfilePosition(positionDev[i]);

            i++;
            module_it++;
        }

        // config parameter will be downloaded in any case to check whether
        // all parameter are correctly uploaded/stored in the MoCon
        D_LOG("update status information")
        dumpStatusInformation(_async, true);

        D_LOG("synchronize PC with MoCon clock")
        // the time gap between the reference time and the current time
        // has not to be to tiny in order to get a valid MoCon cycle time
//        _async.asyncWait(Nice::Time::seconds(2));

        module_it = m_module.begin();
        while (module_it != m_module.end())
        {
            (module_it->second)->getCurrentTime();
            module_it++;
        }

        setIsReachable(true);
        D_LOG("device initialized");

        if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
            m_completion.setDone();
    }

    catch (::Nice::Chat::TimeOutException &e)
    {
        std::string errorMsg = "Motor " + module_it->first + " of device "
                + m_config->name()
                + " couldn't be initialized. Communication Timeout.";
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::Dev::InitException, e, errorMsg);
    }

    catch (::Basda::MoCon::MotorInMotionException &e)
    {
        std::string errorMsg = "Motor " + module_it->first + " of device "
                + m_config->name()
                + " is still in motion. Couldn't be initialized.";
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::Dev::InitException, e, errorMsg);
    }

    catch (::Basda::MoCon::ParamMissingException &e)
    {
        std::string errorMsg = "Motor " + module_it->first + " of device "
                + m_config->name()
                + " couldn't be initialized. A parameter is missing.";
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::Dev::InitException, e, errorMsg);
    }

    catch (::Basda::MoCon::NoAmpplifierException &e)
    {
        std::string errorMsg = "Motor " + module_it->first + " of device "
                + m_config->name()
                + " couldn't be initialized. Amplifier is missing.";
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::Dev::InitException, e, errorMsg);
    }

    catch (::Basda::MoCon::MicrostepResolutionException &e)
    {
        std::string errorMsg = "Motor " + module_it->first + " of device "
                + m_config->name()
                + " couldn't be initialized. The microsteps are not "
                        "supported by that amplifier.";
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::Dev::InitException, e, errorMsg);
    }

    catch (Basda::MoCon::CheckSumException &e)
    {
        std::string errorMsg = "Motor " + module_it->first + " of device "
                + m_config->name()
                + " is still in motion. Couldn't be initialized.";
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::Dev::InitException, e, errorMsg);
    }

    catch (::Basda::MoCon::DumpStatusInformationException &e)
    {
        std::string errorMsg = "Could not update status information of device "
                + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::Dev::InitException, e, errorMsg);
    }
} /* DeviceAsync */

void Basda::MoConNDevice::deinit(Basda::DeviceAsync &_async)
{
    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::DEINIT);
    m_completion.start(Basda::Command::Action::DEINIT);
    _async.asyncStatus(Basda::Command::Action::DEINIT, 100);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
}

void Basda::MoConNDevice::activate(Basda::DeviceAsync &_async)
{
    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::ACTIVATE);
    m_completion.start(Basda::Command::Action::ACTIVATE);
    _async.asyncStatus(Basda::Command::Action::ACTIVATE, 100);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
}

void Basda::MoConNDevice::deactivate(Basda::DeviceAsync &_async)
{
    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::DEACTIVATE);
    m_completion.start(Basda::Command::Action::DEACTIVATE);
    _async.asyncStatus(Basda::Command::Action::DEACTIVATE, 100);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
}

void Basda::MoConNDevice::addProperties()
{
    Nice::JointPtrMap children = m_config->node("MOD")->children();

    if (children.size() == 0)
    {
        std::string errorMsg = "No modules defined!";
        F_THROW(::Basda::DevException, errorMsg);
    }

    std::vector<double> v(children.size(), 0);
    m_config->getWithDefault<std::vector<double> >(
            Basda::Mocca::Dev::PropertyName::limit(), v);

    Nice::BitSet bs((unsigned int) children.size(), 0);
    m_config->getWithDefault<Nice::BitSet>(
            Basda::Mocca::Dev::PropertyName::atHome(), bs);
    m_config->getWithDefault<Nice::BitSet>(
            Basda::Mocca::MoCon::varMotionComplete(), bs);
    m_config->getWithDefault<Nice::BitSet>(
            Basda::Mocca::Dev::PropertyName::moving(), bs);

    std::vector<double> init(children.size(), 0);
    m_config->getWithDefault<Nice::NPointVar>(
            Basda::Mocca::MoCon::varMoconEncoderPosition(), init);
    m_config->getWithDefault<Nice::NPointVar>(
            Basda::Mocca::Dev::PropertyName::absoluteEncoderPosition(), init);
    m_config->getWithDefault<Nice::NPointVar>(
            Basda::Mocca::Dev::PropertyName::incrementalEncoderPosition(),
            init);
    m_config->getWithDefault<Nice::NPointVar>(
            Basda::Mocca::Dev::PropertyName::velocity(), init);

    m_config->leaf(Basda::Mocca::MoCon::varMoconEncoderPosition())
            ->getAttributeWithDefault<std::string>("UNIT", "steps");
    m_config->leaf(Basda::Mocca::Dev::PropertyName::absoluteEncoderPosition())
            ->getAttributeWithDefault<std::string>("UNIT", "steps");
    m_config->leaf(
            Basda::Mocca::Dev::PropertyName::incrementalEncoderPosition())
            ->getAttributeWithDefault<std::string>("UNIT", "steps");
    m_config->leaf(Basda::Mocca::Dev::PropertyName::velocity())
            ->getAttributeWithDefault<std::string>("UNIT", "steps/ms");

    Nice::SeqString ss;
    m_config->getWithDefault<Nice::SeqString>(
            Basda::Mocca::MoCon::varLastFatalError(), ss);

//     m_config->setAtNode<bool>( "VAR.TRACE.INFO.TRACING", false );
//     m_config->setAtNode<int>( "VAR.TRACE.INFO.TRACED_VALUES", 0 );
} /* addProperties */

void Basda::MoConNDevice::chat(std::string _cardNo,
        std::string _commandID,
        std::string _moduleNo,
        std::string _selectID,
        std::string _parameter,
        std::string _numberOfLines,
        Basda::DeviceAsync &_async)
{
    W_LOG( "Depreciated method! chat on card " << _cardNo << " module " << _moduleNo);

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::CHAT);
    m_completion.start(Basda::Command::Action::DONTPARSE);

    unsigned int commandID;
    unsigned int cardNo;
    unsigned int moduleNo;
    unsigned int selectID;
    int numberOfLines;
    std::stringstream s;
    s << _commandID;
    s >> commandID;
    s.clear();
    s << _cardNo;
    s >> cardNo;
    s.clear();
    s << _moduleNo;
    s >> moduleNo;
    s.clear();
    s << _selectID;
    s >> selectID;
    s.clear();
    s << _numberOfLines;
    s >> numberOfLines;
    s.clear();

    if (m_module.begin() != m_module.end())
    {
        _async.asyncStatus(Basda::Command::Action::DONTPARSE, 0);
        ((m_module.begin())->second)->chat(cardNo, commandID, moduleNo,
                                           selectID, _parameter, numberOfLines);
        _async.asyncStatus(Basda::Command::Action::DONTPARSE, 100);
        if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
            m_completion.setDone();
    }
    else
    {
        std::string errorMsg = "No module available.";
        m_completion.setFatal(errorMsg, Basda::DevException());
        F_THROW(::Basda::DevException, errorMsg);
    }
} /* chat */

std::string Basda::MoConNDevice::dontParse(Basda::DeviceAsync &_async)
{
    W_LOG("Depreciated method! dontParse");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::DONTPARSE);
    m_completion.start(Basda::Command::Action::DONTPARSE);

    std::string ret;
    if (m_module.begin() != m_module.end())
    {
        _async.asyncStatus(Basda::Command::Action::DONTPARSE, 0);
        ((m_module.begin())->second)->dontParse(ret);
        _async.asyncStatus(Basda::Command::Action::DONTPARSE, 100);
        if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
            m_completion.setDone();
    }
    else
    {
        std::string errorMsg = "No module available.";
        m_completion.setFatal(errorMsg, Basda::DevException());
        F_THROW(::Basda::DevException, errorMsg);
    }
    return ret;
} /* dontParse */

std::string Basda::MoConNDevice::receiveDataRaw(std::string _cardNo,
        std::string _commandID,
        std::string _moduleNo,
        std::string _numberOfLines,
        Basda::DeviceAsync &_async)
{
    W_LOG( "Depreciated method! receiveData on card " << _cardNo << " module " << _moduleNo);

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::RECEIVEDATARAW);
    m_completion.start(Basda::Command::Action::RECEIVEDATARAW);

    std::string ret;
    unsigned int commandID;
    unsigned int cardNo;
    unsigned int moduleNo;
    int numberOfLines;
    std::stringstream s;
    s << _commandID;
    s >> commandID;
    s.clear();
    s << _cardNo;
    s >> cardNo;
    s.clear();
    s << _moduleNo;
    s >> moduleNo;
    s.clear();
    s << _numberOfLines;
    s >> numberOfLines;
    s.clear();
    if (m_module.begin() != m_module.end())
    {
        _async.asyncStatus(Basda::Command::Action::DONTPARSE, 0);
        ((m_module.begin())->second)->receiveDataRaw(cardNo, commandID,
                                                     moduleNo, ret,
                                                     numberOfLines);
        _async.asyncStatus(Basda::Command::Action::DONTPARSE, 100);
        if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
            m_completion.setDone();
    }
    else
    {
        std::string errorMsg = "No module available.";
        m_completion.setFatal(errorMsg, Basda::DevException());
        F_THROW(::Basda::DevException, errorMsg);
    }
    return ret;
} /* receiveDataRaw */

void Basda::MoConNDevice::moveToHomeStart(Basda::DeviceAsync &_async)
{
    D_LOG("moveToHomeStart");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::MOVETOHOME);
    m_completion.start(Basda::Command::Action::MOVETOHOME);
    moveOutOfLimit(-1, _async);

    m_startPosition.clear(); // needed for method getProgress()

    if (m_completion.state() == Nice::BUSY)
    {
        std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
        try
        {
            while (module_it != m_module.end())
            {
                D_LOG("Motor " << module_it->first << " is moving to home.");
                (module_it->second)->setMotionComplete(false);
                (module_it->second)->moveToHome();
                module_it++;
            }

//            if (!m_stopMoveCmd)
//            {
//                Nice::NPoint position = m_config->node(
//                        Basda::Mocca::MoCon::moconEncoderPosition())
//                        ->get<Nice::NPointVar>();
//
//                unsigned int i = 0;
//                for (i = 0, module_it = m_module.begin();
//                        i < position.size() && module_it != m_module.end(); i++, module_it++)
//                {
//                    if (position.at(i) != 0)
//                    {
//                        D_LOG("Position of motor " << module_it->first << " of device " << m_config->name() << " wasn't zero after home search. "
//                        "Will set to zero now.");
//                        (module_it->second)->setProfilePosition(0);
//                    }
//                }
//            }
        }

        catch (::Basda::MoCon::MotorSettingsIncompleteException &e)
        {
            stop();
            setMotionComplete(true);
            std::string errorMsg =
                    "Home search is not available. Stopped movement of device "
                            + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoConFunctionException, e, errorMsg)
        }

        catch (::Basda::MoCon::MotorOffException &e)
        {
            stop();
            setMotionComplete(true);
            std::string errorMsg =
                   "MoCon motor off. Stopped movement of device "
                            + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoCon::MotorOffException, e, errorMsg)
        }

        catch (::Basda::MoConFunctionException &e)
        {
            stop();
            setMotionComplete(true);
            std::string errorMsg =
                    "MoCon function error. Stopped movement of device "
                            + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoConFunctionException, e, errorMsg)
        }

        catch (::Basda::MoCon::MotionErrorException &e)
        {
            stop();
            setMotionComplete(true);
            try
            {
                dumpStatusInformation(_async);
            }

            catch (::Basda::MoCon::DumpStatusInformationException &ex)
            {
                m_completion.setError(e.what(), ex);
                e.addLoggerObject(ex.log());
                std::string errorMsg = "MoCon motion error. Stopped movement of device "
                        + m_config->name();
                m_completion.setError(errorMsg, e);
                E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg)
            }
            std::string errorMsg =
                    "MoCon motion error. Stopped movement of device "
                            + m_config->name();
            m_completion.setError(errorMsg,
                                  Basda::MoCon::MotionErrorException(e));
            E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg);
        }

        catch (::Basda::MoCon::OutOfRangeException &e)
        {
            stop();
            setMotionComplete(true);
            std::string errorMsg = "MoCon motion error. Stopped movement of device "
                    + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoConFunctionException, e, errorMsg)
        }
   }
} /* moveToHomeStart */

void Basda::MoConNDevice::moveToHomeWait(Basda::DeviceAsync &_async)
{
    D_LOG("moveToHomeWait");

    if (m_completion.state() == Nice::BUSY)
    {
        std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
        try
        {
            _async.asyncStatus(Basda::Command::Action::MOVETOHOME, -1);

            Nice::BitSet motionComplete;
            motionComplete = 0;

            while (!isMotionComplete(motionComplete))
            {
            	module_it = m_module.begin();
                for (int i = 0; i < motionComplete.depth; i++)
                {
                    // search for the first motor that is moving
                    if (motionComplete.test(i) == 0)
                        i = motionComplete.depth;
                    else
                    	module_it++;
                }

                if (module_it != m_module.end())
                    (module_it->second)->waitForEvent();

                _async.asyncStatus(Basda::Command::Action::MOVETOHOME, Basda::Completion::STATUS);

                if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
                    m_completion.setDone();
            }

            _async.asyncStatus(Basda::Command::Action::MOVETOHOME, 100);
            if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
                m_completion.setDone();
        }

        catch (::Basda::MoConFunctionException &e)
        {
            stop();
            setMotionComplete(true);
            std::string errorMsg =
                    "MoCon function error. Stopped movement of device "
                            + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoConFunctionException, e, errorMsg)
        }

        catch (::Basda::MoCon::MotionErrorException &e)
        {
            stop();
            setMotionComplete(true);
            try
            {
                dumpStatusInformation(_async);
            }

            catch (::Basda::MoCon::DumpStatusInformationException &ex)
            {
                m_completion.setError(e.what(), ex);
                e.addLoggerObject(ex.log());
                std::string errorMsg = "MoCon motion error. Stopped movement of device "
                        + m_config->name();
                m_completion.setError(errorMsg, e);
                E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg)
            }
            std::string errorMsg =
                    "MoCon motion error. Stopped movement of device "
                            + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg);
        }
    }
} /* moveToHomeWait */

void Basda::MoConNDevice::moveToHomeSingleStart(int _motor,
        Basda::DeviceAsync &_async)
{
    D_LOG("moveToHomeSingleStart " << _motor);

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::MOVETOHOMESINGLE);
    m_completion.start(Basda::Command::Action::MOVETOHOMESINGLE);

    if (_motor > -1)
    {
        int motor = 0;
        moveOutOfLimit(_motor, _async);

        m_startPosition.clear(); // needed for method getProgress()

        if (m_completion.state() == Nice::BUSY)
        {
            std::map<std::string, MoConModulePtr>::iterator module_it =
                    m_module.begin();
            try
            {
                while (module_it != m_module.end())
                {
                    if (motor == _motor)
                    {
                        D_LOG("Motor " << module_it->first << " is moving to home.");
                        (module_it->second)->setMotionComplete(false);
                        (module_it->second)->moveToHome();
                    }
                    motor++;
                    module_it++;
                }

//            if (!m_stopMoveCmd)
//            {
//                Nice::NPoint position = m_config->node(
//                        Basda::Mocca::MoCon::moconEncoderPosition())
//                        ->get<Nice::NPointVar>();
//
//                unsigned int i = 0;
//                for (i = 0, module_it = m_module.begin();
//                        i < position.size() && module_it != m_module.end(); i++, module_it++)
//                {
//                    if (position.at(i) != 0)
//                    {
//                        D_LOG("Position of motor " << module_it->first << " of device " << m_config->name() << " wasn't zero after home search. "
//                        "Will set to zero now.");
//                        (module_it->second)->setProfilePosition(0);
//                    }
//                }
//            }
            }

            catch (::Basda::MoCon::MotorSettingsIncompleteException &e)
            {
                stop();
                setMotionComplete(true);
                std::string errorMsg =
                        "Home search is not available. Stopped movement of device "
                                + m_config->name();
                m_completion.setError(errorMsg, e);
                E_THROW(::Basda::MoConFunctionException, e, errorMsg)
            }

            catch (::Basda::MoCon::MotorOffException &e)
            {
                stop();
                setMotionComplete(true);
                std::string errorMsg =
                    "MoCon motor off. Stopped movement of device "
                            + m_config->name();
                m_completion.setError(errorMsg, e);
                E_THROW(::Basda::MoCon::MotorOffException, e, errorMsg)
            }

            catch (::Basda::MoConFunctionException &e)
            {
                stop();
                setMotionComplete(true);
                std::string errorMsg =
                        "MoCon function error. Stopped movement of device "
                                + m_config->name();
                m_completion.setError(errorMsg, e);
                E_THROW(::Basda::MoConFunctionException, e, errorMsg)
            }

            catch (::Basda::MoCon::MotionErrorException &e)
            {
                stop();
                setMotionComplete(true);
                try
                {
                    dumpStatusInformation(_async);
                }

                catch (::Basda::MoCon::DumpStatusInformationException &ex)
                {
                    m_completion.setError(e.what(), ex);
                    e.addLoggerObject(ex.log());
                    std::string errorMsg = "MoCon motion error. Stopped movement of device "
                            + m_config->name();
                    m_completion.setError(errorMsg, e);
                    E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg)
                }
                std::string errorMsg =
                        "MoCon motion error. Stopped movement of device "
                                + m_config->name();
                m_completion.setError(errorMsg, e);
                E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg);
            }

            catch (::Basda::MoCon::OutOfRangeException &e)
            {
                stop();
                setMotionComplete(true);
                std::string errorMsg = "MoCon motion error. Stopped movement of device "
                        + m_config->name();
                m_completion.setError(errorMsg, e);
                E_THROW(::Basda::MoConFunctionException, e, errorMsg)
            }
        }
    }
    else
        moveToHome(_async);
} /* moveToHomeSngleStart */

void Basda::MoConNDevice::moveToHomeSingleWait(Basda::DeviceAsync &_async)
{
    D_LOG("moveToHomeSingleWait");
    moveToHomeWait(_async);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
} /* moveToHomeSingleWait */

void Basda::MoConNDevice::moveToPositiveLimitStart(Basda::DeviceAsync &_async)
{
    D_LOG("moveToPositiveLimit");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::MOVETOPOSITIVELIMIT);
    m_completion.start(Basda::Command::Action::MOVETOPOSITIVELIMIT);

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    try
    {
        m_startPosition = getDeviceEncoderPosition();
        m_currentPosition = m_startPosition;
        m_targetPositions.clear();

        while (module_it != m_module.end())
        {
            D_LOG("Motor " << module_it->first << " is moving to positive limit.");
            (module_it->second)->setMotionComplete(false);
            m_targetPositions.push_back((module_it->second)->moveToPositiveLimit());

            module_it++;
        }
    }

    catch (::Basda::MoCon::MotorOffException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon motor off. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotorOffException, e, errorMsg)
    }

    catch (::Basda::MoConFunctionException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon function error. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoConFunctionException, e, errorMsg)
    }

    catch (::Basda::MoCon::MotionErrorException &e)
    {
        stop();
        setMotionComplete(true);
        try
        {
            dumpStatusInformation(_async);
        }

        catch (::Basda::MoCon::DumpStatusInformationException &ex)
        {
            m_completion.setError(e.what(), ex);
            e.addLoggerObject(ex.log());
            std::string errorMsg = "MoCon motion error. Stopped movement of device "
                    + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg)
        }
        std::string errorMsg = "MoCon motion error. Stopped movement of device "
                + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg);
    }
} /* moveToPositiveLimitStart */

void Basda::MoConNDevice::moveToPositiveLimitWait(Basda::DeviceAsync &_async)
{
    D_LOG("moveToPositiveLimitWait");
    completion(Basda::Command::Action::MOVETOPOSITIVELIMIT, _async);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
} /* moveToPositiveLimitWait */

void Basda::MoConNDevice::moveToNegativeLimitStart(Basda::DeviceAsync &_async)
{
    D_LOG("moveToNegativeLimit");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::MOVETONEGATIVELIMIT);
    m_completion.start(Basda::Command::Action::MOVETONEGATIVELIMIT);

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    try
    {
        m_startPosition = getDeviceEncoderPosition();
        m_currentPosition = m_startPosition;
        m_targetPositions.clear();

        while (module_it != m_module.end())
        {
            D_LOG("Motor " << module_it->first << " is moving to negative limit.");
            (module_it->second)->setMotionComplete(false);
            m_targetPositions.push_back((module_it->second)->moveToNegativeLimit());

            // indicate the execution of a standard move command
            module_it++;
        }
    }

    catch (::Basda::MoCon::MotorOffException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon motor off. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotorOffException, e, errorMsg)
    }

    catch (::Basda::MoConFunctionException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon function error. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoConFunctionException, e, errorMsg)
    }

    catch (::Basda::MoCon::MotionErrorException &e)
    {
        stop();
        setMotionComplete(true);
        try
        {
            dumpStatusInformation(_async);
        }

        catch (::Basda::MoCon::DumpStatusInformationException &ex)
        {
            m_completion.setError(e.what(), ex);
            e.addLoggerObject(ex.log());
            std::string errorMsg = "MoCon motion error. Stopped movement of device "
                    + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg)
        }
        std::string errorMsg = "MoCon motion error. Stopped movement of device "
                + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg);
    }
}

void Basda::MoConNDevice::moveToNegativeLimitWait(Basda::DeviceAsync &_async)
{
    D_LOG("moveToNegativeLimitWait");
    completion(Basda::Command::Action::MOVETONEGATIVELIMIT, _async);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
}

void Basda::MoConNDevice::moveToLimitStart(const Nice::NPoint &_limit,
        Basda::DeviceAsync &_async)
{
    D_LOG("moveToLimit");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::MOVETOLIMIT);
    m_completion.start(Basda::Command::Action::MOVETOLIMIT);

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    try
    {
        std::vector<double>::const_iterator limit_it;
        std::vector<double>::const_iterator currentPosition_it;
        m_startPosition = getDeviceEncoderPosition();
        m_currentPosition = m_startPosition;
        m_targetPositions.clear();

        for (limit_it = _limit.begin(), module_it = m_module.begin(), currentPosition_it = m_currentPosition.begin();
        		limit_it != _limit.end() && module_it != m_module.end() && currentPosition_it != m_currentPosition.end();
        		module_it++, limit_it++, currentPosition_it++)
        {
            if ((*limit_it) == Basda::Limit::SOFTWARE_LIMIT)
            {
                try
                {
                	if ((module_it->second)->isAtLimit() < Basda::Limit::SOFTWARE_LIMIT)
                	{
                        (module_it->second)->setMotionComplete(false);
						m_targetPositions.push_back(
								(module_it->second)->moveToPositiveLimit());
		                D_LOG(module_it->first << " is moving to positive software limit");
                	}
                }
                catch (::Basda::MoCon::MotorInPosLimitException &e)
                {
                    (module_it->second)->setMotionComplete(true);
                    D_LOG(module_it->first << " is already in positive software limit");
                }
            }
            else if (*limit_it == -Basda::Limit::SOFTWARE_LIMIT)
            {
                try
                {
                	if ((module_it->second)->isAtLimit() > -Basda::Limit::SOFTWARE_LIMIT)
                	{
                	    U3_LOG(1)
                        (module_it->second)->setMotionComplete(false);
						m_targetPositions.push_back(
								(module_it->second)->moveToNegativeLimit());
		                D_LOG(module_it->first << " is moving to negative software limit");
                	}
				}
                catch (::Basda::MoCon::MotorInNegLimitException &e)
                {
                    (module_it->second)->setMotionComplete(true);
                    D_LOG(module_it->first << " is already in negative software limit");
                }
            }
            else if ((*limit_it) == Basda::Limit::HARDWARE_LIMIT)
            {
                try
                {
                    if ((module_it->second)->isAtLimit() < Basda::Limit::HARDWARE_LIMIT)
                    {
                        (module_it->second)->setMotionComplete(false);
                        m_targetPositions.push_back(
                                (module_it->second)->moveToPositiveLimit(false));
                        D_LOG(module_it->first << " is moving to positive hardware limit");
                    }
                }
                catch (::Basda::MoCon::MotorInPosLimitException &e)
                {
                    (module_it->second)->setMotionComplete(true);
                    D_LOG(module_it->first << " is already in positive hardware limit");
                }
            }
            else if (*limit_it == -Basda::Limit::HARDWARE_LIMIT)
            {
                try
                {
                    if ((module_it->second)->isAtLimit() > -Basda::Limit::HARDWARE_LIMIT)
                    {
                        (module_it->second)->setMotionComplete(false);
                        m_targetPositions.push_back(
                                (module_it->second)->moveToNegativeLimit(false));
                        D_LOG(module_it->first << " is moving to negative hardware limit");
                    }
                }
                catch (::Basda::MoCon::MotorInNegLimitException &e)
                {
                    (module_it->second)->setMotionComplete(true);
                    D_LOG(module_it->first << " is already in negative hardware limit");
                }
            }
            else
            	m_targetPositions.push_back(*currentPosition_it);
        }
    }

    catch (::Basda::MoCon::MotorOffException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon motor off. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotorOffException, e, errorMsg)
    }

    catch (::Basda::MoConFunctionException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon function error. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoConFunctionException, e, errorMsg)
    }

    catch (::Basda::MoCon::MotionErrorException &e)
    {
        stop();
        setMotionComplete(true);
        try
        {
            dumpStatusInformation(_async);
        }

        catch (::Basda::MoCon::DumpStatusInformationException &ex)
        {
            F_LOG(e)
            U9_LOG(1)
            F_LOG(ex)
            m_completion.setError(e.what(), ex);
            e.addLoggerObject(ex.log());
            std::string errorMsg = "MoCon motion error. Stopped movement of device "
                    + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg)
        }
        std::string errorMsg = "MoCon motion error. Stopped movement of device "
                + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg);
    }
} /* moveToLimitStart */

void Basda::MoConNDevice::moveToLimitWait(Basda::DeviceAsync &_async)
{
    D_LOG("moveToLimitWait");
    completion(Basda::Command::Action::MOVETOLIMIT, _async);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
} /* moveToLimitWait */

void Basda::MoConNDevice::moveOutOfLimit(int _motor, Basda::DeviceAsync &_async)
{
    D_LOG("moveOutOfLimit " << _motor);

    int motor = 0;
    int isAtLimitModule = Basda::Limit::IN_VALID_RANGE;
    Nice::BitSet motionComplete;
    double distance = 0;
    Nice::NPoint distances;

    Nice::JointPtr limitPtr = m_config->node(
            Basda::Mocca::Dev::PropertyName::limit());
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    try
    {
        // do while motor is in limits
        do
        {
            m_startPosition = getDeviceEncoderPosition();
            m_currentPosition = m_startPosition;
            distances.clear();
            distance = 0;

            module_it = m_module.begin();
            motor = 0;
            while (module_it != m_module.end())
            {
                if (_motor == -1 || motor == _motor)
                {
                    isAtLimitModule = (module_it->second)->isAtLimit();
					// move all motor (-1) out of limit or only the selected one
					// if this motor is in harware limit
                    // this will not be done when the motor is in the valid range
                    // or in software limit (in that case the motor is in physically in valid range)
					if (abs(isAtLimitModule) == Basda::Limit::HARDWARE_LIMIT)
					{
						(module_it->second)->setMotionComplete(false);
						distance = (module_it->second)->moveOutOfLimit();
					}
					else
					    // to ignore software limit flags and need to the outer
					    // loop abort criteria
					    isAtLimitModule = Basda::Limit::IN_VALID_RANGE;
                }
				distances.push_back(distance);
                module_it++;
                motor++;
            }

            // wait until movements is done
            m_targetPositions = m_currentPosition + distances;
            while (!isMotionComplete(motionComplete))
            {
                //update completion bar and status information like pos, vel
                _async.asyncStatus(Basda::Command::Action::MOVEOUTOFLIMIT,
                                   (int) getProgress().percent());
                module_it = m_module.begin();
                for (int i = 0; i < motionComplete.depth && module_it != m_module.end(); i++)
                {
                    isAtLimitModule = (module_it->second)->isAtLimit();
                    if (motionComplete.test(i) == 0)
                    {
                        // stop movement immediately when motor is out of limit
                        if (abs(isAtLimitModule)
                                != Basda::Limit::HARDWARE_LIMIT)
                        {
                            stop();
                            m_completion.start(); // to unset the m_completion aborting
                        }
                        break;
                    }
                    else
                    	module_it++;
                }
                if (module_it != m_module.end())
                    (module_it->second)->waitForEvent();
            }
        } while (isAtLimitModule && (m_completion.state() == Nice::BUSY));
    }

    catch (::Basda::MoCon::MotorOffException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon motor off. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotorOffException, e, errorMsg)
    }

    catch (::Basda::MoConFunctionException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon function error. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoConFunctionException, e, errorMsg)
    }

    catch (::Basda::MoCon::MotionErrorException &e)
    {
        stop();
        setMotionComplete(true);
        try
        {
            dumpStatusInformation(_async);
        }

        catch (::Basda::MoCon::DumpStatusInformationException &ex)
        {
            U2_LOG(e)
            U3_LOG(ex)
            m_completion.setError(e.what(), ex);
            e.addLoggerObject(ex.log());
            std::string errorMsg = "MoCon motion error. Stopped movement of device "
                    + m_config->name();
            m_completion.setError(errorMsg, e);
            F_LOG(e)
            E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg)
        }
        std::string errorMsg = "MoCon motion error. Stopped movement of device "
                + m_config->name();
        m_completion.setError(errorMsg, Basda::MoCon::MotionErrorException(e));
        E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg);
    }
} /* moveOutOfLimit */

void Basda::MoConNDevice::moveAbsoluteStart(const Nice::NPoint &_absolutePositions,
        Basda::DeviceAsync &_async)
{
    D_LOG("moveAbsolute ");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::MOVEABSOLUTE);
    m_completion.start(Basda::Command::Action::MOVEABSOLUTE);

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    try
    {
        m_startPosition = getDeviceEncoderPosition();
        m_currentPosition = m_startPosition;
        m_targetPositions = _absolutePositions;
        Nice::NPoint::iterator startPosition_it;
        Nice::NPoint::iterator targetPosition_it;
        int i = 0;

        // all motors from the vector targetPosition and maximal the motors in
        // the moConPtrMap will move
        for (startPosition_it = m_startPosition.begin(), targetPosition_it = m_targetPositions.begin(), module_it = m_module.begin();
        		startPosition_it != m_startPosition.end() && targetPosition_it != m_targetPositions.end() && module_it != m_module.end();
        		startPosition_it++, targetPosition_it++, module_it++, i++)
        {
        	// this condition check is needed for the moveSync commands
        	// MoCon will send a invalid instruction in case motor don't need to move but the motor is commanded to move
        	if (*targetPosition_it != *startPosition_it)
        	{
				std::stringstream ss;
				ss << "Motor " << module_it->first << " is moving to absolute position ";
	//            if ((*targetPosition_it > -0.0001 && *targetPosition_it < 0.0001) || (*targetPosition_it < -999999.4 || *targetPosition_it > 999999.4))
					ss.setf(std::ios_base::fixed); //switch on scientific notification
	//            else
	//                ss.unsetf(std::ios_base::fixed); //switch of scientific notification
				ss.precision(0);
				ss << *targetPosition_it << " steps.";
				ss.unsetf(std::ios_base::fixed);
				D_LOG( ss.str() );
				(module_it->second)->setMotionComplete(false);
				(module_it->second)->moveAbsolute((int) *targetPosition_it);
        	}
        	else
        	{
        		D_LOG(m_config->name() << " [" << i << "] is already at the target position. Will not send extra move command.")
        	}
        }
    }

    catch (::Basda::MoCon::MotorOffException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon motor off. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotorOffException, e, errorMsg)
    }

    catch (::Basda::MoConFunctionException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon function error. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoConFunctionException, e, errorMsg)
    }

    catch (::Basda::MoCon::MotionErrorException &e)
    {
        stop();
        setMotionComplete(true);
        try
        {
            dumpStatusInformation(_async);
        }

        catch (::Basda::MoCon::DumpStatusInformationException &ex)
        {
            m_completion.setError(e.what(), ex);
            e.addLoggerObject(ex.log());
            std::string errorMsg = "MoCon motion error. Stopped movement of device "
                    + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg)
        }
        std::string errorMsg = "MoCon motion error. Stopped movement of device "
                + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg);
    }

    catch (::Basda::MoCon::OutOfRangeException &e)
    {
        stop();
        setMotionComplete(true);        std::string errorMsg = "MoCon motion error. Stopped movement of device "
                + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoConFunctionException, e, errorMsg)
    }
} /* moveAbsoluteStart */

void Basda::MoConNDevice::moveAbsoluteWait(Basda::DeviceAsync &_async)
{
    D_LOG("moveAbsoluteWait");
    completion(Basda::Command::Action::MOVEABSOLUTE, _async);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
} /* moveAbsoluteWait */

void Basda::MoConNDevice::moveRelativeStart(const Nice::NPoint &_relativePositions,
        Basda::DeviceAsync &_async)
{
    D_LOG("moveRelative");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::MOVERELATIVE);
    m_completion.start(Basda::Command::Action::MOVERELATIVE);

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    try
    {
    	int i = 0;
        Nice::NPoint absolutePosition;

        Nice::NPoint::const_iterator relativePositions_it;

        m_startPosition = getDeviceEncoderPosition();
        m_currentPosition = m_startPosition;

//        Nice::NPoint currentPosition = getDeviceEncoderPosition();

        // each motor in the argument map have to move to the relative position
        for (relativePositions_it = _relativePositions.begin(), module_it = m_module.begin();
        		relativePositions_it != _relativePositions.end() && module_it != m_module.end();
        		relativePositions_it++, module_it++, i++)
        {
        	// this condition check is needed for the moveSync commands
        	// MoCon will send a invalid instruction in case motor don't need to move but the motor is commanded to move
        	if (*relativePositions_it != 0)
        	{
				// search for the given motor name in the map
				std::stringstream ss;
				ss << "Motor " << module_it->first << " is moving to relative position ";
	//            if ((*relativePositions_it > -0.0001 && *relativePositions_it < 0.0001) || (*relativePositions_it < -999999.4 || *relativePositions_it > 999999.4))
					ss.setf(std::ios_base::fixed); //switch on scientific notification
	//            else
	//                ss.unsetf(std::ios_base::fixed); //switch of scientific notification
				ss.precision(0);
				ss << *relativePositions_it << " steps.";
				ss.unsetf(std::ios_base::fixed);
				D_LOG( ss.str() );
				if (*relativePositions_it != 0)
				{
					(module_it->second)->setMotionComplete(false);
					(module_it->second)->moveRelative((int) *relativePositions_it);
				}
        	}
        	else
        	{
        		D_LOG(m_config->name() << " [" << i << "] is already at the target position. Will not send extra move command.")
        	}
        }
//        m_targetPositions = _relativePositions + currentPosition;
        m_targetPositions = _relativePositions + m_currentPosition;
    }

    catch (::Basda::MoCon::MotorOffException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon motor off. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotorOffException, e, errorMsg)
    }

    catch (::Basda::MoConFunctionException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon function error. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoConFunctionException, e, errorMsg)
    }

    catch (::Basda::MoCon::MotionErrorException &e)
    {
        stop();
        setMotionComplete(true);
        try
        {
            dumpStatusInformation(_async);
        }

        catch (::Basda::MoCon::DumpStatusInformationException &ex)
        {
            m_completion.setError(e.what(), ex);
            e.addLoggerObject(ex.log());
            std::string errorMsg = "MoCon motion error. Stopped movement of device "
                    + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg)
        }
        std::string errorMsg = "MoCon motion error. Stopped movement of device "
                + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg);
    }

    catch (::Basda::MoCon::OutOfRangeException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg = "MoCon motion error. Stopped movement of device "
                + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoConFunctionException, e, errorMsg)
    }
} /* moveRelativeStart */

void Basda::MoConNDevice::moveRelativeWait(Basda::DeviceAsync &_async)
{
    D_LOG("moveRelativeWait");
    completion(Basda::Command::Action::MOVERELATIVE, _async);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
}

void Basda::MoConNDevice::prepareMoveSync(Nice::BitSet _motors)
{
    Nice::BitSet motors = Nice::BitSet(8, 0);

    motors.setValue(_motors.getValue());
    std::stringstream msg;
    msg << "Prepare motors ";
    msg << (motors[0] ? " 1" : "");
    msg << (motors[1] ? " 2" : "");
    msg << (motors[2] ? " 3" : "");
    msg << (motors[3] ? " 4" : "");
    msg << (motors[4] ? " 5" : "");
    msg << (motors[5] ? " 6" : "");
    msg << (motors[6] ? " 7" : "");
    msg << (motors[7] ? " 8" : "");
    msg << " on card " << (m_card.begin()->first) << " for synchronous move.";
    D_LOG(msg.str())

    (m_card.begin()->second)->lockCard();
    (m_card.begin()->second)->setMultiUpdateSettings(motors.getValue());
}

void Basda::MoConNDevice::startMoveSync()
{
    D_LOG("Start synchronous move now.")

    (m_card.begin()->second)->moveMultiUpdate();
    (m_card.begin()->second)->unlockCard();
}

void Basda::MoConNDevice::prepareDirectMove(const Nice::NPoint &_acceleration,
                                            const Nice::NPoint &_velocity,
                                            const Nice::NPoint &_deceleration)
{
    D_LOG("prepareDirectMove");

    std::vector<double>::const_iterator acceleration_it;
    std::vector<double>::const_iterator velocity_it;
    std::vector<double>::const_iterator deceleration_it;
    std::map<std::string, MoConModulePtr>::iterator module_it;

    // set for the velocity of each motor
    for (acceleration_it = _acceleration.begin(), velocity_it = _velocity.begin(), deceleration_it = _deceleration.begin(), module_it = m_module.begin();
            acceleration_it != _acceleration.end() && velocity_it != _velocity.end() && deceleration_it != _deceleration.end() && module_it != m_module.end();
            acceleration_it++, velocity_it++, deceleration_it++, module_it++)
    {
        if (*acceleration_it != 0 && *velocity_it != 0)
        {
            D_LOG( "Set acceleration of motor " << module_it->first << " to " << *acceleration_it << " rev/min")
            (module_it->second)->setBasicSettings(
                    Basda::SelectBasicSettings::MOCON_SELECT_ACCELERATION, *acceleration_it);

            D_LOG( "Set velocity of motor " << module_it->first << " to " << *velocity_it << " rev/min")
            (module_it->second)->setBasicSettings(
                    Basda::SelectBasicSettings::MOCON_SELECT_VELOCITY, *velocity_it);

            D_LOG( "Set deceleration of motor " << module_it->first << " to " << *deceleration_it << " rev/min")
            (module_it->second)->setBasicSettings(
                    Basda::SelectBasicSettings::MOCON_SELECT_DECELERATION, *deceleration_it);

            D_LOG("Initialize motor " << module_it->first << " after configuration changes." )
            (module_it->second)->initializeMotor();
        }
    }
}

void Basda::MoConNDevice::startExternalProfile(const Nice::Date &_date,
        const Nice::NPoint &_positionSequence,
        unsigned int _frequency,
        unsigned int _maxSamplesPerSegment,
        unsigned int _faultTolerance,
        Basda::DeviceAsync &_async)
{
    I_LOG(__FUNCTION__ << " ~ Derotation requested starting at " << _date)
    U2_LOG("derotation requested at " << _date << " with parameter: frequency:" 
            << _frequency << " _maxSamplesPerSegment:" << _maxSamplesPerSegment << " _faultTolerance:" << _faultTolerance);
    m_externalProfileInfo = -1;
    unsigned int minSamplesPerSegment = 5;
    double contingency = 1.1;  // 10% contingency to the MoCon simulation
                               // decrease the number the trigger will raise too late
                               // increase the number the trigger will raise too early
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    Nice::Date currentBlockEndDate;

    // trajectory service (derotator) has only a single motor
    if (module_it != m_module.end())
    {
        m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::STARTEXTERNALPROFILE);
        m_completion.start(Basda::Command::Action::STARTEXTERNALPROFILE);

        /* this signals to getProgress() that we're starting at zero percnet
        */
        m_startPosition.clear();

        _async.asyncStatus(Basda::Command::Action::STARTEXTERNALPROFILE, 0);

        Nice::BitSet motionComplete;
        (module_it->second)->setMotionComplete(false);

        try
        {
            (module_it->second)->clearExternalProfileBuffer();
        }
        catch (Basda::MoCon::NoBufferDefinedException &e)
        {
            //                D_LOG("Initial clear buffer for next profile. Exception ignored.");
        }


        /* this upload time is the time (in seconds) needed for a single sample upload
        * to the mocon, of the order of a few milliseconds
        */
        Nice::Time segmentUploadTime = (module_it->second)->initExternalProfile(
                _frequency, _maxSamplesPerSegment, minSamplesPerSegment,
                _faultTolerance);

        Nice::JointPtrMap children = m_config->node("MOD")->children();
        std::map<std::string, Nice::JointPtr>::iterator children_it = children .begin();

        /* this is typically 5 in the linc-nirvana data sheets; apparently correlated with minSamplesPerSegment
        */
        Nice::U32 segmentsPerBlock =
                (children_it->second)->getAtNode<Nice::U32>(
                        Basda::Mocca::MoCon::cfgDatasheetSegmentsPerBlock());

        double maxNumberOfSegmentsPerBlock = segmentsPerBlock
                * _maxSamplesPerSegment / minSamplesPerSegment;

        /* this is typically 8 ms times 100 for the linc-nirvana derotator cases
        */
        Nice::Time blockUploadTime = segmentUploadTime * maxNumberOfSegmentsPerBlock;

        generateExternalProfile(_date, _positionSequence);
        /* number of bytes reserved here is rounded-down value of
        * bufferSize = 1024*1024 / 8(modules) / 4(32 bit = long int) / 5(traj values, time, vel, pos, acc,jerk)
        * See src/device/mpia/mocon/Module.h
        */
        (module_it->second)->setExternalProfileBufferSize((unsigned int) (6000), true);

        /* An estimate when the first block of position-velocity data of the
        * trajectory is uploaded to the MoCon. Note that this is kept independent of the capacity
        * of 6000 samples in the MoCon RAM or the duration of the entire trajectory (both typically
        * much larger than the maxNumberOfSegmentsPerBlock.
        */
        Nice::Date uploadFinished = Nice::Date::now() + blockUploadTime;

        if (uploadFinished < _date)
            currentBlockEndDate = (module_it->second)->uploadExternalProfile();
        else
        {
            std::string errorMsg = "External profile start is too close ("
                    + _date.toString()
                    + "). Segment uploading will take longer ("
                    + uploadFinished.toString() + ")";
            m_completion.setError(
                    errorMsg,
                    Basda::Dev::MoccaUploadExternalProfileException());
            E_THROW( Basda::Dev::MoccaUploadExternalProfileException, errorMsg)
        }
        (module_it->second)->setExternalProfileStart(
                Basda::ValueStartMode::MOCON_MODE_START_FROM_BEGINNING, _date);

        // I_LOG("Wait for External Profile execution.");
        waitForNextTrigger(_date - blockUploadTime * contingency, _async);
        I_LOG("External Profile starts now.")
        Nice::Date nextTrigger;
        // in case the stop button is pressed, the Mocon will send a motion complete event
        // and the trajectory handling procedure will stop as well

        while (!isMotionComplete(motionComplete))
        {
            // if the next trigger is in the future then wait for it
            if ( currentBlockEndDate - blockUploadTime * contingency > Nice::Date::now())
            {
                nextTrigger = currentBlockEndDate - Nice::Time::seconds(5); // blockUploadTime * contingency ;
                if (!(module_it->second)->isExternalProfileDone())
                {
                    U2_LOG("Current block ends at " << currentBlockEndDate);
                    U2_LOG("Next trigger will be at " << nextTrigger);
                }
                waitForNextTrigger(nextTrigger, _async);
                if (!(module_it->second)->isExternalProfileDone())
                {
                    U2_LOG("Trigger raised for next block at " << nextTrigger << ". Now is: " << Nice::Date::now());
                }
            }

            // upload blocks only when the block end date is in the future
            if (currentBlockEndDate > Nice::Date::now()
                    && !isMotionComplete(motionComplete)
                    && !(module_it->second)->isExternalProfileDone())
            {
                U2_LOG("Upload next block of segments now.");
                currentBlockEndDate = (module_it->second)->uploadExternalProfile();
                if (!(module_it->second)->isExternalProfileDone()) // no log when trajectory is done
                {
                    U2_LOG("Next block of segments are uploaded. Next block should start at " << currentBlockEndDate);
                }
            }

            /* in case the block end date is in the past (because the whole buffer
            * is uploaded) we will wait till we receive the trajectory event
            * or throw an exception when the motion is done but the trajectory not completed
            */
            if (currentBlockEndDate < Nice::Date::now())
            {
                if (!(module_it->second)->isExternalProfileDone())
                {
                    if (!isMotionComplete(motionComplete))
                        (module_it->second)->setExternalProfileStop();
                    break;
                }
                else
                {
                    // optimize predict trajectory end
                    nextTrigger = Nice::Date::now() + Nice::Time::milliSeconds(500);
                    waitForNextTrigger(nextTrigger, _async); // is needed to wait for
                                                             // the completion event
                                                             // at the end of the profile
                }
            }

        }

        try
        {
            D_LOG("clear buffer")
            (module_it->second)->clearExternalProfileBuffer();
        }
        catch (Basda::MoCon::NoBufferDefinedException &e)
        {
//           D_LOG("Initial clear buffer for next profile. Exception ignored.");
        }

        if (!(module_it->second)->isExternalProfileDone())
        {
            std::string errorMsg = "Trigger to upload next external profile segment was too late. Start external profile again.";
            m_completion.setError(
                    errorMsg,
                    Basda::Dev::MoccaUploadExternalProfileException());
            E_THROW(Basda::Dev::MoccaUploadExternalProfileException, errorMsg)
        }
        else
        {
            I_LOG("trajectory done")
            _async.asyncStatus(Basda::Command::Action::STARTEXTERNALPROFILE, 100);
        }

        if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
            m_completion.setDone();
    }
} /* startExternalProfile */

int Basda::MoConNDevice::shinsGetStartingRamp(const Nice::NPoint & _positionSequence, double time_interval_microseconds)
{
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    if(module_it != m_module.end())
    {
        return (module_it->second)->shinsGetStartingRamp(_positionSequence, time_interval_microseconds);
    }
    else
    {
        std::string errorMsg = "Module does' not exist";
        E_LOG(errorMsg);
        throw(std::runtime_error(errorMsg));
    }
}

void Basda::MoConNDevice::shinsStartExternalProfile(const Nice::Date &_date,
                                                    const Nice::NPoint &_positionSequence,
                                                    unsigned int _frequency,
                                                    unsigned int _maxSamplesPerSegment,
                                                    unsigned int _faultTolerance,
                                                    Basda::DeviceAsync &_async)
{
    I_LOG(__FUNCTION__ << " ~ Derotation requested starting at " << _date)
    U2_LOG("derotation requested at " << _date << " with parameter: frequency:" << _frequency << " _maxSamplesPerSegment:" << _maxSamplesPerSegment << " _faultTolerance:" << _faultTolerance);
    m_externalProfileInfo = -1;
    unsigned int minSamplesPerSegment = 5;
    double contingency = 1.1;  // 10% contingency to the MoCon simulation decrease the number the trigger will raise too late increase the number the trigger will raise too early
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    Nice::Date currentBlockEndDate;

    // trajectory service (derotator) has only a single motor
    if(module_it != m_module.end())
    {
        m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::SHINSSTARTEXTERNALPROFILE);
        m_completion.start(Basda::Command::Action::SHINSSTARTEXTERNALPROFILE);

        /* this signals to getProgress() that we're starting at zero percent */
        m_startPosition.clear();

        _async.asyncStatus(Basda::Command::Action::SHINSSTARTEXTERNALPROFILE, 0);

        Nice::BitSet motionComplete;
        (module_it->second)->setMotionComplete(false);

        try
        {
            (module_it->second)->clearExternalProfileBuffer();
        }
        catch(Basda::MoCon::NoBufferDefinedException &e)
        {
            // D_LOG("Initial clear buffer for next profile. Exception ignored.");
        }


        /* this upload time is the time (in seconds) needed for a single sample upload
        * to the mocon, of the order of a few milliseconds */
        Nice::Time segmentUploadTime = (module_it->second)->initExternalProfile(_frequency, _maxSamplesPerSegment, minSamplesPerSegment, _faultTolerance);

        Nice::JointPtrMap children = m_config->node("MOD")->children();
        std::map<std::string, Nice::JointPtr>::iterator children_it = children .begin();

        /* this is typically 5 in the linc-nirvana data sheets; apparently correlated with minSamplesPerSegment */
        Nice::U32 segmentsPerBlock = (children_it->second)->getAtNode<Nice::U32>(Basda::Mocca::MoCon::cfgDatasheetSegmentsPerBlock());

        double maxNumberOfSegmentsPerBlock = segmentsPerBlock*_maxSamplesPerSegment / minSamplesPerSegment;

        /* this is typically 8 ms times 100 for the linc-nirvana derotator cases */
        Nice::Time blockUploadTime = segmentUploadTime * maxNumberOfSegmentsPerBlock;

        shinsGenerateExternalProfile(_date, _positionSequence);
        Nice::Date effective_start_date = (module_it->second)->shinsGetEffectiveProfileStartDate();
        U2_LOG("Effective_start_date : " << effective_start_date << "; derotation start date : " << _date << "; blockUploadTime : " << blockUploadTime);
        /* number of bytes reserved here is rounded-down value of
        * bufferSize = 1024*1024 / 8(modules) / 4(32 bit = long int) / 5(traj values, time, vel, pos, acc,jerk)
        * See src/device/mpia/mocon/Module.h */

        if(_faultTolerance == 0)
        {
            throw(std::runtime_error("external profile temporarily interdicted"));
        }

        (module_it->second)->setExternalProfileBufferSize((unsigned int) (6000), true);

        /* An estimate when the first block of position-velocity data of the
        * trajectory is uploaded to the MoCon. Note that this is kept independent of the capacity
        * of 6000 samples in the MoCon RAM or the duration of the entire trajectory (both typically
        * much larger than the maxNumberOfSegmentsPerBlock. */
        Nice::Date uploadFinished = Nice::Date::now() + blockUploadTime;

        if(uploadFinished < effective_start_date)
        {
            currentBlockEndDate = (module_it->second)->shinsUploadExternalProfile();
        }
        else
        {
            std::string errorMsg = "External profile start is too close (" + effective_start_date.toString() + "). Segment uploading will take longer (" + uploadFinished.toString() + ")";
            m_completion.setError(errorMsg, Basda::Dev::MoccaUploadExternalProfileException());
            E_THROW( Basda::Dev::MoccaUploadExternalProfileException, errorMsg);
        }
        (module_it->second)->setExternalProfileStart(Basda::ValueStartMode::MOCON_MODE_START_FROM_BEGINNING, effective_start_date);

        // I_LOG("Wait for External Profile execution.");
        shinsWaitForNextTrigger(effective_start_date - blockUploadTime * contingency, _async);
        I_LOG("External Profile starts now.")
        Nice::Date nextTrigger;
        // in case the stop button is pressed, the Mocon will send a motion complete event
        // and the trajectory handling procedure will stop as well
        while(!isMotionComplete(motionComplete))
        {
            // if the next trigger is in the future then wait for it
            if ( currentBlockEndDate - blockUploadTime * contingency > Nice::Date::now())
            {
                nextTrigger = currentBlockEndDate - Nice::Time::seconds(5); // blockUploadTime * contingency ;
                if (!(module_it->second)->isExternalProfileDone())
                {
                    U2_LOG("Current block ends at " << currentBlockEndDate);
                    U2_LOG("Next trigger will be at " << nextTrigger);
                }
                shinsWaitForNextTrigger(nextTrigger, _async);
                if (!(module_it->second)->isExternalProfileDone())
                {
                    U2_LOG("Trigger raised for next block at " << nextTrigger << ". Now is: " << Nice::Date::now());
                }
            }

            // upload blocks only when the block end date is in the future
            if (currentBlockEndDate > Nice::Date::now() && !isMotionComplete(motionComplete) && !(module_it->second)->isExternalProfileDone())
            {
                U2_LOG("Upload next block of segments now.");
                currentBlockEndDate = (module_it->second)->shinsUploadExternalProfile();
                if(!(module_it->second)->isExternalProfileDone()) // no log when trajectory is done
                {
                    U2_LOG("Next block of segments are uploaded. Next block should start at " << currentBlockEndDate);
                }
            }

            /* in case the block end date is in the past (because the whole buffer
            * is uploaded) we will wait till we receive the trajectory event
            * or throw an exception when the motion is done but the trajectory not completed */
            if(currentBlockEndDate < Nice::Date::now())
            {
                if(!(module_it->second)->isExternalProfileDone())
                {
                    if(!isMotionComplete(motionComplete))
                    {
                        (module_it->second)->setExternalProfileStop();
                    }
                    break;
                }
                else
                {
                    // optimize predict trajectory end
                    nextTrigger = Nice::Date::now() + Nice::Time::milliSeconds(1000);
                    shinsWaitForNextTrigger(nextTrigger, _async); // is needed to wait for the completion event at the end of the profile
                }
            }

        }

        try
        {
            D_LOG("clear buffer")
            (module_it->second)->clearExternalProfileBuffer();
        }
        catch (Basda::MoCon::NoBufferDefinedException &e)
        {
//           D_LOG("Initial clear buffer for next profile. Exception ignored.");
        }

        if(!(module_it->second)->isExternalProfileDone())
        {
            std::string errorMsg = "Trigger to upload next external profile segment was too late. Start external profile again.";
            m_completion.setError(errorMsg, Basda::Dev::MoccaUploadExternalProfileException());
            E_THROW(Basda::Dev::MoccaUploadExternalProfileException, errorMsg);
        }
        else
        {
            I_LOG("trajectory done")
            _async.asyncStatus(Basda::Command::Action::SHINSSTARTEXTERNALPROFILE, 100);
        }

        if((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
            m_completion.setDone();
    }
} /* shinsStartExternalProfile */

int Basda::MoConNDevice::sharkDerotatorBacklashProcedure(int procedure)
{
    int result = EXIT_FAILURE;
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

        m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::SHINSBACKLASHPROCEDURE);
        m_completion.start(Basda::Command::Action::SHINSBACKLASHPROCEDURE);
//        _async.asyncStatus(Basda::Command::Action::SHINSBACKLASHPROCEDURE, 0);

        Nice::BitSet motionComplete;
        (module_it->second)->setMotionComplete(false);

    try
    {
        result = (module_it->second)->sharkDerotatorBacklashProcedure(procedure);
    }
    catch(...)
    {
        E_LOG(__FUNCTION__);
        throw;
    }

    {
        I_LOG("Backlash Procedure Done")
//        _async.asyncStatus(Basda::Command::Action::SHINSBACKLASHPROCEDURE, 100);
    }

    if((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
    return result;
}

void Basda::MoConNDevice::waitForNextTrigger(Nice::Date _date, Basda::DeviceAsync &_async)
{
    // @toDo: stop also the while loop when the Mocon cycle time is reached
    // for a next upload
    Nice::BitSet motionComplete;
    Nice::Time time;

    while (_date > Nice::Date::now() && !isMotionComplete(motionComplete))
    {
//        U6_LOG("next trigger is " << _date << ". current time is " << Nice::Date::now())
        time = _date - Nice::Date::now();
        if (time > Nice::Time::milliSeconds(500))
            time = Nice::Time::milliSeconds(500);

        if (time > Nice::Time::microSeconds(1))
            _async.asyncWait(time);

        int index ;
        try
        {
            index = (m_module.begin()->second)->getExternalProfileInfo();
        }
        catch (Basda::MoCon::NoBufferDefinedException &e)
        {
            /* May we end up here if the stop was sent and isMotionComplete()
            * does not catch this correctly? .. RJM 2019-11-22
            */
            return ;
        }

        if (index > -1)
        {
            if (index != m_externalProfileInfo)
            {
                U2_LOG("Trajectory segment " << index << " of " << m_externalProfileSize - 1 << " is in progress. ")
                m_externalProfileInfo = index;
            }
            _async.asyncStatus(Basda::Command::Action::STARTEXTERNALPROFILE, (int)(100.0 / m_externalProfileSize * index));
        }
    }
} /* waitForNextTrigger */

void Basda::MoConNDevice::shinsWaitForNextTrigger(Nice::Date _date, Basda::DeviceAsync &_async)
{
    // @toDo: stop also the while loop when the Mocon cycle time is reached for a next upload
    Nice::BitSet motionComplete;
    Nice::Time time;

    while (_date > Nice::Date::now() && !isMotionComplete(motionComplete))
    {
//        U6_LOG("next trigger is " << _date << ". current time is " << Nice::Date::now())
        int index ;
        try
        {
            index = (m_module.begin()->second)->getExternalProfileInfo();
        }
        catch (Basda::MoCon::NoBufferDefinedException &e)
        {
            /* May we end up here if the stop was sent and isMotionComplete()
            * does not catch this correctly? .. RJM 2019-11-22 */
            U9_LOG("No Buffer defined exception");
            return ;
        }

        if (index > -1)
        {
            if (index != m_externalProfileInfo)
            {
                U2_LOG("Trajectory segment " << index << " of " << m_externalProfileSize - 1 << " is in progress. ")
                m_externalProfileInfo = index;
            }
            std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
            _async.asyncStatus(Basda::Command::Action::SHINSSTARTEXTERNALPROFILE, (module_it->second)->ExternalProfileCompletion());
        }

        time = _date - Nice::Date::now();
        if (time > Nice::Time::milliSeconds(500))
            time = Nice::Time::milliSeconds(500);

        if (time > Nice::Time::microSeconds(1))
            _async.asyncWait(time);

    }
} /* shinsWaitForNextTrigger */

void Basda::MoConNDevice::generateExternalProfile(const Nice::Date &_date, const Nice::NPoint &_positionSequence)
{
    U2_LOG("Generate trajectory starting at " << _date)
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    // trajectory service has only a single motor
    if (module_it != m_module.end())
    {
        try
        {
            (module_it->second)->calculateTransition(_date, _positionSequence);
            (module_it->second)->fitTrajectory();
            (module_it->second)->validateExternalProfile();
//            E_LOG("Error derotation momentarily interdicted");
//            throw(std::runtime_error("Error derotation momentarily interdicted"));
            m_externalProfileSize = (module_it->second)->bufferExternalProfile();
        }

        catch (Basda::MoCon::NoBufferDefinedException &e)
        {
//          D_LOG("Initial clear buffer for next profile. Exception ignored.");
        }
    }
} /* generateExternalProfile */


void Basda::MoConNDevice::shinsGenerateExternalProfile(const Nice::Date &_date, const Nice::NPoint &_positionSequence)
{
    U2_LOG("Generate trajectory starting at " << _date)
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    // trajectory service has only a single motor
    if (module_it != m_module.end())
    {
        try
        {
            (module_it->second)->calculateTransition(_date, _positionSequence);
            (module_it->second)->shinsFitTrajectory();
            (module_it->second)->validateExternalProfile();
//            E_LOG("Error derotation momentarily interdicted");
//            throw(std::runtime_error("Error derotation momentarily interdicted"));
            
            m_externalProfileSize = (module_it->second)->bufferExternalProfile();
        }

        catch (Basda::MoCon::NoBufferDefinedException &e)
        {
//          D_LOG("Initial clear buffer for next profile. Exception ignored.");
        }
    }
} /* shinsGenerateExternalProfile */

void Basda::MoConNDevice::changeExternalProfile(
        const Nice::Date &_date,
        const Nice::NPoint &_positionSequence)
{
    // This procedure changes the current trajectory and validates the changes
    // including the trajectory transition.
    // If the transition is not valid it increases the transition time and starts
    // from beginning.
    // Finally it overwrites the current trajectory
    I_LOG("Trajectory will be changed at " << _date)
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    // trajectory service has only a single motor
    if (module_it != m_module.end())
    {
        try
        {
            double basicResolution = m_config->getAtNode<Nice::U16>(
                            std::string("MOD.") + m_config->node("MOD")->children().begin()->first + "."
                                    + Basda::Mocca::MoCon::cfgDatasheetBasicResolution());
            double basicVelocity = m_config->getAtNode<double>(
                            std::string("MOD.") + m_config->node("MOD")->children().begin()->first + "."
                                    + Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight());

            bool transitionIsNotValid = true;
            Nice::Time transitionLength = Nice::Time::seconds(
                    (getDeviceEncoderPosition()[0] - _positionSequence[0])
                    / (basicVelocity * basicResolution / 60.0));

            if (transitionLength < Nice::Time::seconds(1))
                transitionLength = Nice::Time::seconds(1);

            while (transitionIsNotValid)
            {
                try
                {
                    (module_it->second)->calculateTransition(_date, _positionSequence, transitionLength);
                    (module_it->second)->fitTrajectory();
                    (module_it->second)->validateExternalProfile();
                    m_externalProfileSize = (module_it->second)->bufferExternalProfile();
                    I_LOG("Trajectory successful changed.")
                    transitionIsNotValid = false;
                }

                catch (::Basda::MoCon::SegmentLengthUnderrunException &e)
                {
                    transitionLength += Nice::Time::seconds(1);
                    D_LOG("SegmentLengthUnderrunException. Procedure increases time to " << transitionLength << "and try to fit again.")
                }

                catch (Basda::MoCon::ProfileTransitionException &e)
                {
                    transitionLength += Nice::Time::seconds(1);
                    D_LOG("Transition to short. Procedure increases time to " << transitionLength << "and try to fit again.")
                }

                catch (Basda::MoCon::InvalidProfileException &e)
                {
                    D_LOG(e)
                    transitionLength += Nice::Time::seconds(1);
                    D_LOG("Transition to short. Procedure increases time to " << transitionLength << "and try to fit again.")
                }

                catch (Basda::MoCon::ProfileTransitionStartToEarlyException &e)
                {
                    D_LOG("Transition to new trajectory was not feasible.")
                    E_THROW(Basda::Dev::MoccaChangeExternalProfileException, "Transition to new trajectory was not feasible.")
                }
            }
        }

        catch (Basda::MoCon::NoBufferDefinedException &e)
        {
//                D_LOG("Initial clear buffer for next profile. Exception ignored.");
        }
    }
} /* changeExternalProfile */

void Basda::MoConNDevice::prepareExternalProfile(const Nice::SeqSeqInt &_segmentsX,
        const Nice::SeqSeqInt &_segmentsY,
        Basda::DeviceAsync &_async)
{
    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::PREPAREEXTERNALPROFILE);
    m_completion.start(Basda::Command::Action::PREPAREEXTERNALPROFILE);

    m_startPosition = getDeviceEncoderPosition();
    m_currentPosition = m_startPosition;
    m_targetPositions = m_startPosition;

U4_LOG(_segmentsX)
U4_LOG(_segmentsY)
    std::map<std::string, MoConModulePtr>::iterator moduleX_it = m_module.begin();
    std::map<std::string, MoConModulePtr>::iterator moduleY_it = m_module.begin();
    moduleY_it++;

    bool moveX = !(_segmentsX[0][0] == 0 && _segmentsX[0][1] == 0 &&
                   _segmentsX[0][3] == 0 && _segmentsX[0][4] == 0);
    bool moveY = !(_segmentsY[0][0] == 0 && _segmentsY[0][1] == 0 &&
                   _segmentsY[0][3] == 0 && _segmentsY[0][4] == 0);

    if (moveX)
    {
        try
        {
            (moduleX_it->second)->clearExternalProfileBuffer();
        }

        catch (Basda::MoCon::NoBufferDefinedException &e)
        {
            //                D_LOG("Initial clear buffer for next profile. Exception ignored.");
        }
        (moduleX_it->second)->setExternalProfileBufferSize((unsigned int) (6000), true);
        (moduleX_it->second)->uploadExternalProfile(_segmentsX);
    }

    if (moveY)
    {
        try
        {
            (moduleY_it->second)->clearExternalProfileBuffer();
        }

        catch (Basda::MoCon::NoBufferDefinedException &e)
        {
            //                D_LOG("Initial clear buffer for next profile. Exception ignored.");
        }
        (moduleY_it->second)->setExternalProfileBufferSize((unsigned int) (6000), true);
        (moduleY_it->second)->uploadExternalProfile(_segmentsY);
    }

    m_startPosition[0] = _segmentsX[0][2];
    m_startPosition[1] = _segmentsY[0][2];
    m_currentPosition = m_startPosition;
    m_targetPositions[0] = _segmentsX[_segmentsX.size()-1][2];
    m_targetPositions[1] = _segmentsY[_segmentsY.size()-1][2];

    _async.asyncStatus(Basda::Command::Action::PREPAREEXTERNALPROFILE, 100);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
} /* prepareExternalProfile */

void Basda::MoConNDevice::startExternalProfile(Basda::DeviceAsync &_async)
{
    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::STARTEXTERNALPROFILE);
    m_completion.start(Basda::Command::Action::STARTEXTERNALPROFILE);

    std::map<std::string, MoConModulePtr>::iterator moduleX_it = m_module.begin();
    std::map<std::string, MoConModulePtr>::iterator moduleY_it = m_module.begin();
    moduleY_it++;

    if (m_startPosition[0] != m_targetPositions[0])
    {
        (moduleX_it->second)->setExternalProfileStart(
                        Basda::ValueStartMode::MOCON_MODE_START_FROM_BEGINNING, Nice::Date::microSeconds(-1));
        (moduleX_it->second)->setMotionComplete(false);
    }
    else
        (moduleX_it->second)->setMotionComplete(true);

    if (m_startPosition[1] != m_targetPositions[1])
    {
        (moduleY_it->second)->setExternalProfileStart(
                        Basda::ValueStartMode::MOCON_MODE_START_FROM_BEGINNING, Nice::Date::microSeconds(-1));
        (moduleY_it->second)->setMotionComplete(false);
    }
    else
        (moduleY_it->second)->setMotionComplete(true);

    _async.asyncStatus(Basda::Command::Action::STARTEXTERNALPROFILE, 100);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
} /* startExternalProfile */

void Basda::MoConNDevice::shinsStartExternalProfile(Basda::DeviceAsync &_async)
{
    U6_LOG(__FUNCTION__ << " ~ DeviceAsync");
    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::SHINSSTARTEXTERNALPROFILE);
    m_completion.start(Basda::Command::Action::SHINSSTARTEXTERNALPROFILE);

    std::map<std::string, MoConModulePtr>::iterator moduleX_it = m_module.begin();
    std::map<std::string, MoConModulePtr>::iterator moduleY_it = m_module.begin();
    moduleY_it++;

    if (m_startPosition[0] != m_targetPositions[0])
    {
        (moduleX_it->second)->setExternalProfileStart(
                        Basda::ValueStartMode::MOCON_MODE_START_FROM_BEGINNING, Nice::Date::microSeconds(-1));
        (moduleX_it->second)->setMotionComplete(false);
    }
    else
        (moduleX_it->second)->setMotionComplete(true);

    if (m_startPosition[1] != m_targetPositions[1])
    {
        (moduleY_it->second)->setExternalProfileStart(
                        Basda::ValueStartMode::MOCON_MODE_START_FROM_BEGINNING, Nice::Date::microSeconds(-1));
        (moduleY_it->second)->setMotionComplete(false);
    }
    else
        (moduleY_it->second)->setMotionComplete(true);

    _async.asyncStatus(Basda::Command::Action::SHINSSTARTEXTERNALPROFILE, 100);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
} /* shinsStartExternalProfile */

void Basda::MoConNDevice::completion(std::string _cmd, Basda::DeviceAsync &_async)
{
    D_LOG("completion " << _cmd);

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    try
    {
        Nice::BitSet motionComplete;
//        m_startPosition = getDeviceEncoderPosition();
//        m_currentPosition = m_startPosition;
//
        _async.asyncStatus(_cmd, 0);
        motionComplete = 0;
        while (!isMotionComplete(motionComplete))
        {
            //update completion bar and status information like pos, vel
            _async.asyncStatus(_cmd, (int) getProgress().percent());

            for (int i = 0; i < motionComplete.depth; i++)
            {
                if (motionComplete.test(i) == 0)
                    i = motionComplete.depth;
                else
                	module_it++;
            }
            if (module_it != m_module.end())
                (module_it->second)->waitForEvent();
        }

        module_it = m_module.begin();
        if (m_completion.command<Basda::Command::Constant>() == Command::STARTEXTERNALPROFILE || m_completion.command<Basda::Command::Constant>() == Command::SHINSSTARTEXTERNALPROFILE)
        {
            while (module_it != m_module.end())
            {
                try
                {
                    (module_it->second)->clearExternalProfileBuffer();
                }

                catch (Basda::MoCon::NoBufferDefinedException &e)
                {
        //                W_LOG(e)
                }
            }
            module_it++;
        }

        _async.asyncStatus(_cmd, 100);
        m_completion.setPercent(100);
    }

    catch (::Basda::MoConFunctionException &e)
    {
        stop();
        setMotionComplete(true);
        std::string errorMsg =
                "MoCon function error. Stopped movement of device "
                        + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoConFunctionException, e, errorMsg)
    }

    catch (::Basda::MoCon::MotionErrorException &e)
    {
        stop();
        setMotionComplete(true);
        try
        {
            dumpStatusInformation(_async);
        }

        catch (::Basda::MoCon::DumpStatusInformationException &ex)
        {
            m_completion.setError(e.what(), ex);
            e.addLoggerObject(ex.log());
            std::string errorMsg = "MoCon motion error. Stopped movement of device "
                    + m_config->name();
            m_completion.setError(errorMsg, e);
            E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg)
        }
        std::string errorMsg = "MoCon motion error. Stopped movement of device "
                + m_config->name();
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg);
    }
} /* competion */

Nice::Completion Basda::MoConNDevice::getProgress()
{
	double percent = 100;
	double tmp = 1000;

    std::vector<double>::const_iterator startPosition_it = m_startPosition.begin();
    std::vector<double>::const_iterator targetPositions_it = m_targetPositions.begin();
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    m_currentPosition = m_config->node(
            Basda::Mocca::MoCon::varMoconEncoderPosition())->leaf()
            ->get<Nice::NPointVar>();

    if (!m_startPosition.empty())
    {
	// compute the percentage of the movement of each motor and divide it by
	// the number of motors
	for (std::vector<double>::const_iterator currentPosition_it = m_currentPosition.begin();
			currentPosition_it != m_currentPosition.end(), targetPositions_it != m_targetPositions.end();
			++currentPosition_it, ++startPosition_it, targetPositions_it++, ++module_it)
	{
            Nice::BitSet motionComplete;
            motionComplete = 0;

            // some times the MoCon finished the movement
            // but the target position is still not reached
            // that can happen when the motor moves into the limits
            // therefore the check isMotionComplete()
		if (!(module_it->second)->isMotionComplete() && !Nice::Helper::fuzzyCompare(*startPosition_it, *targetPositions_it))
		{
			if (!Nice::Helper::fuzzyCompare(*startPosition_it, *currentPosition_it))
			{
				//            (current position - start position) / (start position - target position)
				tmp = 100 * fabs(*currentPosition_it - *startPosition_it) / fabs(*startPosition_it - *targetPositions_it);

			        if (tmp < percent)
			            percent = tmp;
			}
			else
			    percent = 0;
		}
	}
    }
    else
    {
        Nice::BitSet motionComplete;
        motionComplete = 0;

		if (isMotionComplete(motionComplete))
			percent = 100;
		else
			percent = -1; // percentage unknown during home search
    }

    m_completion.setPercent((int) percent);

    return m_completion;
}

void Basda::MoConNDevice::abort()
{
    D_LOG("abort");

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    while (module_it != m_module.end())
    {
        // stop all motors with a deceleration
        if (m_completion.command<Basda::Command::Constant>() == Command::STARTEXTERNALPROFILE || m_completion.command<Basda::Command::Constant>() == Command::SHINSSTARTEXTERNALPROFILE)
        {
            D_LOG("Abort profiles " << module_it->first)
            try
            {
                (module_it->second)->setExternalProfileStop();
                (module_it->second)->clearExternalProfileBuffer();
            }

            catch (Basda::MoCon::NoBufferDefinedException &e)
            {
                W_LOG(e)
            }
        }
        else
        {
            D_LOG("Abort moving " << module_it->first)
            (module_it->second)->abort();
        }
        module_it++;
    }
    m_completion.setAbort();
}

void Basda::MoConNDevice::stop()
{
    D_LOG("stop");

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    while (module_it != m_module.end())
    {
        if (m_completion.command<Basda::Command::Constant>() == Command::STARTEXTERNALPROFILE || m_completion.command<Basda::Command::Constant>() == Command::SHINSSTARTEXTERNALPROFILE)
        {
            D_LOG("Stop profiles " << module_it->first)
            try
            {
                (module_it->second)->setExternalProfileStop();
                (module_it->second)->clearExternalProfileBuffer();
            }
            catch (Basda::MoCon::NoBufferDefinedException &e)
            {
                // W_LOG(e)
            }
        }
        else
        {
            // abort all motors that are otherwise in some simple trapezoidal profile
            D_LOG("Stop moving " << module_it->first)
            (module_it->second)->stop();
        }
        module_it++;
    }
    m_completion.setStop();
} /* stop */

Nice::NPoint Basda::MoConNDevice::getPosition()
{
    W_LOG("Deprecated method! Will be removed in the next version! Use getDeviceEncoderPosition() instead.")
    return getDeviceEncoderPosition();
}

Nice::NPoint Basda::MoConNDevice::getDeviceEncoderPosition()
{
    D_LOG("Get device position of all motors.")
    Nice::NPoint position;
    int positionInSteps;
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    // ask for the current position of each motor and
    // save it in a vector
    while (module_it != m_module.end())
    {
        D_LOG("getPosition of " << module_it->first);
        positionInSteps = 0;
        positionInSteps = (module_it->second)->getMEncPosition();
        //convert the position in the user defined unit
        position.push_back(positionInSteps);
        module_it++;
    }

    // write the vector back in the POSITION property
    m_config->setAtNode<Nice::NPointVar>(
            Basda::Mocca::MoCon::varMoconEncoderPosition(), position);
    return position;
}

Nice::NPoint Basda::MoConNDevice::getAbsoluteEncoderPosition()
{
    D_LOG("Get absolute encoder position of all motors.")
    Nice::NPoint position;
    int positionInSteps;
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    // ask for the current position of each motor, convert it to millimeter and
    // save it in a vector
    while (module_it != m_module.end())
    {
        D_LOG("getPosition of " << module_it->first);
        positionInSteps = 0;
        try
        {
            positionInSteps = (module_it->second)->getAEncPosition();
        }

        catch (::Basda::MoCon::CmdForAEncException & e)
        {
            E_THROW( ::Basda::Dev::MoccaCmdForAEncException, e, "Couldn't get absolute encoder position of device " << module_it->first)
        }
        //convert the position in the user defined unit
        position.push_back(positionInSteps);
        module_it++;
    }

    // write the vector back in the POSITION property
    m_config->setAtNode<Nice::NPointVar>(
            Basda::Mocca::Dev::PropertyName::absoluteEncoderPosition(),
            position);
    return position;
}

Nice::NPoint Basda::MoConNDevice::getIncrementalEncoderPosition()
{
    D_LOG("Get incremental encoder position of all motors.")
    Nice::NPoint position;
    int positionInSteps;
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    // ask for the current position of each motor, convert it to millimeter and
    // save it in a vector
    while (module_it != m_module.end())
    {
        D_LOG("getPosition of " << module_it->first);
        positionInSteps = 0;
        try
        {
            positionInSteps = (module_it->second)->getIEncPosition();
        }

        catch (::Basda::MoCon::CmdForIEncException & e)
        {
            E_THROW( ::Basda::Dev::MoccaCmdForIEncException, e, "Couldn't get incremental encoder position of device " << module_it->first)
        }
        //convert the position in the user defined unit
        position.push_back(positionInSteps);
        module_it++;
    }

    // write the vector back in the POSITION property
    m_config->setAtNode<Nice::NPointVar>(
            Basda::Mocca::Dev::PropertyName::incrementalEncoderPosition(),
            position);
    return position;
}

void Basda::MoConNDevice::setPosition(const Nice::NPoint &_position)
{
    D_LOG("setPosition");
    Nice::NPoint position;

    std::vector<double>::const_iterator module_it;
    std::map<std::string, MoConModulePtr>::iterator jt;

    // change the absolute position value of the MoCon to _position.
    // The motor will not move!
    for (module_it = _position.begin(), jt = m_module.begin();
            module_it != _position.end() && jt != m_module.end(); module_it++, jt++)
    {
        D_LOG( "Set position of motor " << jt->first << " to " << *module_it << " steps")
        (jt->second)->setProfilePosition(*module_it);
    }
}

Nice::NPoint Basda::MoConNDevice::getVelocity()
{
    D_LOG("Get current velocity of all motors.");
    Nice::NPoint velocity;

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    // ask for the current velocity of each motor and save it in a vector
    while (module_it != m_module.end())
    {
        velocity.push_back((module_it->second)->getVelocity());
        module_it++;
    }

    // write the vector back in the VELOCITY property
    m_config->setAtNode<Nice::NPointVar>(
            Basda::Mocca::Dev::PropertyName::velocity(), velocity);
    return velocity;
}

Nice::SeqSeqDouble Basda::MoConNDevice::getBasicSettings()
{
    D_LOG("Get basic setting of all motors.");
    Nice::SeqSeqDouble basicSettings;

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    // ask for the basic settings of each motor
    while (module_it != m_module.end())
    {
        (module_it->second)->getBasicSettings();
        module_it++;
    }

    Nice::JointPtrMap children = m_config->node("MOD")->children();
    std::map<std::string, Nice::JointPtr>::iterator children_it =
            children.begin();

    while (children_it != children.end())
    {
        Nice::SeqDouble basicSetting;

        basicSetting.push_back(m_config->getAtNode<Nice::U16>(
                std::string("MOD.") + children_it->first + "."
                        + Basda::Mocca::MoCon::cfgDatasheetBasicProfile()));
        basicSetting.push_back(m_config->getAtNode<Nice::U16>(
                std::string("MOD.") + children_it->first + "."
                        + Basda::Mocca::MoCon::cfgDatasheetBasicResolution()));
        basicSetting.push_back(m_config->getAtNode<double>(
                std::string("MOD.") + children_it->first + "."
                        + Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStraight()));
        basicSetting.push_back(m_config->getAtNode<double>(
                std::string("MOD.") + children_it->first + "."
                        + Basda::Mocca::MoCon::cfgDatasheetBasicVelocityStart()));
        basicSetting.push_back(m_config->getAtNode<Nice::U32>(
                std::string("MOD.") + children_it->first + "."
                        + Basda::Mocca::MoCon::cfgDatasheetBasicVelocityAcceleration()));
        basicSetting.push_back(m_config->getAtNode<Nice::U32>(
                std::string("MOD.") + children_it->first + "."
                        + Basda::Mocca::MoCon::cfgDatasheetBasicVelocityDeceleration()));
        basicSetting.push_back(m_config->getAtNode<Nice::U32>(
                std::string("MOD.") + children_it->first + "."
                        + Basda::Mocca::MoCon::cfgDatasheetBasicJerk()));

        basicSettings.push_back(basicSetting);
        children_it++;
    }

    return basicSettings;
}

void Basda::MoConNDevice::setVelocitySetting(const Nice::NPoint &_velocity)
{
    D_LOG("setVelocitySetting");

    std::vector<double>::const_iterator velocity_it;
    std::map<std::string, MoConModulePtr>::iterator module_it;

    // set for the velocity of each motor
    for (velocity_it = _velocity.begin(), module_it = m_module.begin();
            velocity_it != _velocity.end() && module_it != m_module.end();
            velocity_it++, module_it++)
    {
        D_LOG( "Set velocity of motor " << module_it->first << " to " << *velocity_it << " rev/min")
        (module_it->second)->setBasicSettings(
                Basda::SelectBasicSettings::MOCON_SELECT_VELOCITY, *velocity_it);

        D_LOG("Initialize motor " << module_it->first << " after configuration chances." )
        (module_it->second)->initializeMotor();
    }
}

void Basda::MoConNDevice::setAccelerationSetting(const Nice::NPoint &_acceleration)
{
    D_LOG("setAccelerationSetting");

    std::vector<double>::const_iterator acceleration_it;
    std::map<std::string, MoConModulePtr>::iterator module_it;

    // set for the acceleration of each motor
    for (acceleration_it = _acceleration.begin(), module_it = m_module.begin();
            acceleration_it != _acceleration.end() && module_it != m_module.end();
            acceleration_it++, module_it++)
    {
        D_LOG( "Set acceleration of motor " << module_it->first << " to " << *acceleration_it << " rev/min")
        (module_it->second)->setBasicSettings(
                Basda::SelectBasicSettings::MOCON_SELECT_ACCELERATION, *acceleration_it);

        D_LOG("Initialize motor " << module_it->first << " after configuration chances." )
        (module_it->second)->initializeMotor();
    }
}

void Basda::MoConNDevice::setDecelerationSetting(const Nice::NPoint &_deceleration)
{
    D_LOG("setDecelerationSetting");

    std::vector<double>::const_iterator deceleration_it;
    std::map<std::string, MoConModulePtr>::iterator module_it;

    // set for the deceleration of each motor
    for (deceleration_it = _deceleration.begin(), module_it = m_module.begin();
            deceleration_it != _deceleration.end() && module_it != m_module.end();
            deceleration_it++, module_it++)
    {
        D_LOG( "Set deceleration of motor " << module_it->first << " to " << *deceleration_it << " rev/min")
        (module_it->second)->setBasicSettings(
                Basda::SelectBasicSettings::MOCON_SELECT_DECELERATION, *deceleration_it);

        D_LOG("Initialize motor " << module_it->first << " after configuration chances." )
        (module_it->second)->initializeMotor();
    }
}

void Basda::MoConNDevice::setJerkSetting(const Nice::NPoint &_jerk)
{
    D_LOG("setJerkSetting");

    std::vector<double>::const_iterator jerk_it;
    std::map<std::string, MoConModulePtr>::iterator module_it;

    // set for the jerk of each motor
    for (jerk_it = _jerk.begin(), module_it = m_module.begin();
            jerk_it != _jerk.end() && module_it != m_module.end();
            jerk_it++, module_it++)
    {
        D_LOG( "Set jerk of motor " << module_it->first << " to " << *jerk_it << " rev/min")
        (module_it->second)->setBasicSettings(
                Basda::SelectBasicSettings::MOCON_SELECT_JERK, *jerk_it);

        D_LOG("Initialize motor " << module_it->first << " after configuration chances." )
        (module_it->second)->initializeMotor();
    }
}

bool Basda::MoConNDevice::isMoving(Nice::BitSet &_isMoving)
{
    D_LOG("isMoving");
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    int i = 0;
    _isMoving.setDepth((unsigned int) m_module.size());
    while (module_it != m_module.end())
    {
        _isMoving[i] = (module_it->second)->isMoving();
        module_it++;
        i++;
    }

    m_config->setAtNode<Nice::BitSet>(Basda::Mocca::Dev::PropertyName::moving(),
                                      _isMoving);

    return (_isMoving.count() > 0);
}

bool Basda::MoConNDevice::isAtLimit(Nice::NPoint &_limit)
{
    D_LOG("isAtLimit");
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    Nice::BitSet bs;
    int i = 0;

    bs.setDepth((unsigned int) m_module.size());
    // update all motor limit flags first

    _limit.clear();
    while (module_it != m_module.end())
    {
        _limit.push_back((module_it->second)->isAtLimit());
        bs[i] = (bool) fabs(_limit[i]);
        module_it++;
        i++;
    }

    m_config->node(Basda::Mocca::Dev::PropertyName::limit())
            ->set<Nice::NPointVar>(_limit);

    return (bs.count() == (unsigned int) bs.depth);
}

bool Basda::MoConNDevice::isAtHome(Nice::BitSet &_atHome)
{
    D_LOG("isAtHome");
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    int i = 0;

    _atHome.setDepth((unsigned int) m_module.size());

    while (module_it != m_module.end())
    {
        _atHome[i] = (module_it->second)->isAtHome();
        module_it++;
        i++;
    }

    m_config->node(Basda::Mocca::Dev::PropertyName::atHome())->set<Nice::BitSet>(
            _atHome);

    return _atHome.count() == _atHome.getDepth();
}

bool Basda::MoConNDevice::isMotionComplete(Nice::BitSet &_motion)
{
    D_LOG("isMotionComplete");
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    int i = 0;
    _motion.setDepth((unsigned int) m_module.size());
    while (module_it != m_module.end())
    {
        // set the MOTION_COMPLETE flag to true if one of the module has done the motion
        _motion[i] = (module_it->second)->isMotionComplete();
        module_it++;
        i++;
    }

    m_config->setAtNode<Nice::BitSet>(Basda::Mocca::MoCon::varMotionComplete(), _motion);

    Nice::BitSet _bs;
    _bs = _motion;
    _bs = ~_bs;

    return (_bs.value == 0);
}

void Basda::MoConNDevice::setMotionComplete(bool _complete)
{
    D_LOG("setMotionComplete");
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    Nice::BitSet bs((Nice::U32)m_module.size(), 0);
    int i = 0;
    while (module_it != m_module.end())
    {
        // set the motion flag to true if one of the module is in motion
        (module_it->second)->setMotionComplete(_complete);
        bs[i] = _complete;
        module_it++;
        i++;
    }

    m_config->setAtNode<Nice::BitSet>(
            Basda::Mocca::MoCon::varMotionComplete(), bs);
}

void Basda::MoConNDevice::setLinkTimeout(Nice::Time _tcpConnectionTimeout)
{
    D_LOG("Set link timeout.")
    std::map<std::string, MoConCardPtr>::iterator card_it = m_card.begin();

    // set for the deceleration of each motor
    while (card_it != m_card.end())
    {
        D_LOG("set link timeout of module " << card_it->first << " to " << _tcpConnectionTimeout << " seconds");
        (card_it->second)->lockCard();
        try
        {
            (card_it->second)->setLinkTimeout((unsigned int)_tcpConnectionTimeout.toSeconds());
        }

        catch (::Basda::MPIA::WrongCmdNrException &e)
        {
            E_LOG("Your firmware is deprecated. Command getLinkTimeout (36) is unknown.")
            E_LOG("Please update the firmware at least to COS_XC161 V2.19, Nov 23 2012, Motion Controller V1.27, Nov 23 2012")
        }

        (card_it->second)->unlockCard();
        card_it++;
    }
}

Nice::SeqTime Basda::MoConNDevice::getLinkTimeout()
{
    D_LOG("Get link timeout.")
    std::map<std::string, MoConCardPtr>::iterator card_it = m_card.begin();

    Nice::SeqTime tcpConnectionTimeout;

    while (card_it != m_card.end())
    {
        D_LOG("get link timeout of module " << card_it->first);
        (card_it->second)->lockCard();
        try
        {
            unsigned int timeout = (card_it->second)->getLinkTimeout();
            D_LOG( "link timeout of module " << card_it->first << " is set to " << timeout << " seconds.")
            tcpConnectionTimeout.push_back(Nice::Time::seconds(timeout));
        }

        catch (::Basda::MPIA::WrongCmdNrException &e)
        {
            E_LOG("Your firmware is deprecated. Command getLinkTimeout (37) is unknown.")
            E_LOG("Please update the firmware at least to COS_XC161 V2.19, Nov 23 2012, Motion Controller V1.27, Nov 23 2012")
            tcpConnectionTimeout.push_back(Nice::Time::seconds(3600));
        }

        (card_it->second)->unlockCard();
        card_it++;
    }

    return tcpConnectionTimeout;
}

Nice::NPoint Basda::MoConNDevice::getReferenceTime()
{
    D_LOG("Get reference time from all modules.");
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    Nice::NPoint referenceTime;

    // each motor in the argument map have to move home
    while (module_it != m_module.end())
    {
        D_LOG("synchronize time of module " << module_it->first);
        referenceTime.push_back((double) (module_it->second)->getReferenceTime());
        module_it++;
    }
    return referenceTime;
}

Nice::NPoint Basda::MoConNDevice::getCurrentTime()
{
    D_LOG("Get current time from all modules.");
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    Nice::NPoint currentTime;

    // each motor in the argument map have to move home
    while (module_it != m_module.end())
    {
        D_LOG("get current time of module " << module_it->first);
        currentTime.push_back((double) (module_it->second)->getCurrentTime());
        module_it++;
    }
    return currentTime;
}

Nice::SeqBitSet Basda::MoConNDevice::getPositionSwitchStatus()
{
    D_LOG("Get status of all position switches from all motors.")
    Nice::SeqBitSet positionSwitchStatus;

    Nice::BitSet status;
    status.setDepth(m_config->getWithDefault(Basda::Mocca::Dev::PropertyName::cfgSwitchDepth(), 32));
    Nice::BitSet mask = m_config->getWithDefault<Nice::BitSet>(Basda::Mocca::Dev::PropertyName::cfgSwitchMask(), Nice::BitSet(8, 255));

    status.setValue(0);
    std::map<std::string, MoConCardPtr>::iterator card_it = m_card.begin();

    try
    {
        // ask for the current position of each motor, convert it to millimeter and
        // save it in a vector
        while (card_it != m_card.end())
        {
            D_LOG("getPositionSwitchStatus of " << card_it->first);
            status = 0;
            try
            {
                (card_it->second)->lockCard();
            }

            catch (Basda::MPIA::ModuleAlreadyRegisteredException &e)
            {
            }

            status = (card_it->second)->getDigitalInLong(0);
            status &= mask;
            D_LOG("position switch status of " << card_it->first << " is " << status);
            (card_it->second)->unlockCard();

            //convert the position in the user defined unit
            positionSwitchStatus.push_back(status);
            card_it++;
        }
    }

    catch (::Basda::MPIA::ModuleIsInUseException &e)
    {
        E_THROW(::Basda::Dev::MoccaCmdRejectedByDeviceException, e, "getPositionSwitchStatus() of card " << card_it->first << " was rejected by device.")
    }


    return positionSwitchStatus;
}

void Basda::MoConNDevice::setCollision(Nice::SeqPoint _collisions)
{
    D_LOG("Indicate all motors that have a collision.");
    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    unsigned int i = 0;
    while ((module_it != m_module.end()) && (i < _collisions.size()))
    {
        module_it->second->setCollision(_collisions[i].x() != 0, _collisions[i].y() != 0);
        module_it++;
        i++;
    }
}

void Basda::MoConNDevice::setIsReachable(const bool _state)
{
    D_LOG("Device " << m_config->name() << " is " << (_state ? "" : "not ") << "reachable.");
    Nice::Guard guard(m_mutex);
    m_config->setAtNode<bool>(Basda::Mocca::Dev::PropertyName::isReachable(),
                              _state);
    m_isReachable = _state;
}

bool Basda::MoConNDevice::isReachable()
{
    D_LOG("Device " << m_config->name() << " is " << (m_isReachable ? "" : "not ") << "reachable.");
    Nice::Guard guard(m_mutex);
    return m_isReachable;
}

void Basda::MoConNDevice::dumpStatusInformation(Basda::DeviceAsync &_async,
                                                bool _compareParameter)
{
    D_LOG("update status information");

    m_completion = Nice::Completion::exec<Basda::Command::Constant>(Command::DUMPSTATUSINFORMATION);
    m_completion.start(Basda::Command::Action::DUMPSTATUSINFORMATION);

    Nice::BitSet bs;
    Nice::NPoint np;

    int percentTotal = 0;
    Nice::JointPtrMap children = m_config->node("MOD")->children();
    std::map<std::string, Nice::JointPtr>::iterator children_it =
            children.begin();

    std::map<std::string, MoConModulePtr>::iterator module_it =
            m_module.begin();
    _async.asyncStatus(Basda::Command::Action::DUMPSTATUSINFORMATION, 0);
    m_completion.setPercent(0);

    int percent;
    if (!m_module.empty())
        percent = 100 / 8;
    else
    {
        std::string errorMsg = "No modules are available in device "
                + m_config->name() + ". Open connection to hardware first!";
        m_completion.setFatal(errorMsg,
                              Basda::MoCon::DumpStatusInformationException());
        F_THROW(::Basda::MoCon::DumpStatusInformationException, errorMsg);
    }

    try
    {
        getDeviceEncoderPosition();
        _async.asyncStatus(Basda::Command::Action::DUMPSTATUSINFORMATION, percentTotal += percent);
        m_completion.setPercent(percentTotal);
        isMoving(bs);
        _async.asyncStatus(Basda::Command::Action::DUMPSTATUSINFORMATION, percentTotal += percent);
        m_completion.setPercent(percentTotal);
        isAtHome(bs);
        _async.asyncStatus(Basda::Command::Action::DUMPSTATUSINFORMATION, percentTotal += percent);
        m_completion.setPercent(percentTotal);
        isAtLimit(np);
        _async.asyncStatus(Basda::Command::Action::DUMPSTATUSINFORMATION, percentTotal += percent);
        m_completion.setPercent(percentTotal);
        getPositionSwitchStatus();
    }

    catch (::Nice::Chat::TimeOutException &e)
    {
        std::string errorMsg = "Timeout while asking for status information. "
                "Call method dumpStatusInformation() manually!";
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
    }

    catch (::Basda::MPIA::ModuleIsInUseException &e)
    {
        W_LOG( "Couldn't lock card! Update of Position-Switch-Status not possible! "
        "Call method dumpStatusInformation() manually!");
    }

    catch (::Basda::Dev::MoccaCmdRejectedByDeviceException &e)
    {
        W_LOG( "Couldn't lock card! Update of Position-Switch-Status not possible! "
        "Call method dumpStatusInformation() manually!");
    }

    catch (::Nice::Exception &e)
    {
        std::string errorMsg = "Call method dumpStatusInformation() manually!";
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
    }

    // for each motor download the motor configuration and status information
    while (children_it != children.end())
    {
        std::string address =
                (children_it->second)->getWithDefault<std::string>(
                        Basda::Mocca::MoCon::cfgConnectionAddress(),
                        "tcp://192.168.1.1:4000");
        int cardNo = (children_it->second)->getWithDefault<int>(
                Basda::Mocca::MoCon::cfgConnectionCard(), Basda::MOCON);
        int moduleNo = (children_it->second)->getWithDefault<int>(
                Basda::Mocca::MoCon::cfgConnectionModule(), 1);

        std::string connectionID = createConnectionID(address, cardNo,
                                                      moduleNo);

        if ((module_it = m_module.find(connectionID)) != m_module.end())
        {
            D_LOG( "update status information of module " << module_it->first << " (" << children_it->first << ")")
            try
            { // use the absEnc and iEnc method!!
                int encoderType =
                        m_config->getAtNode<int>(
                                std::string("MOD.") + children_it->first + "."
                                        + Basda::Mocca::MoCon::cfgDatasheetEncoderType());
                try
                {
                    if (encoderType == Basda::EncoderType::ABSOLUTE_ENCODER
                            || encoderType
                                    == Basda::EncoderType::INCREMENTAL_AND_ABSOLUTE_ENCODER)
                        (module_it->second)->getAEncPosition();
                }

                catch (::Basda::MoCon::CmdForAEncException &e)
                {
                    W_LOG(e)
                }

                try
                {
                    if (encoderType == Basda::EncoderType::INCREMENTAL_ENCODER
                            || encoderType
                                    == Basda::EncoderType::INCREMENTAL_AND_ABSOLUTE_ENCODER)
                        (module_it->second)->getIEncPosition();
                }

                catch (::Basda::MoCon::CmdForIEncException &e)
                {
                    W_LOG(e)
                }

                if ((module_it->second)->configParameterUploadRequired())
                {
                    I_LOG("Compare MoCon settings with config file settings")
                }
                else
                {
                    I_LOG("Download MoCon settings of " << children_it->first)
                }
                (module_it->second)->getBasicSettings(_compareParameter);
                (module_it->second)->getMotorSettings(_compareParameter);
                if ((module_it->second)->getMotorType()
                        == Basda::MotorType::SERVO)
                    (module_it->second)->getServoLoopSettings(_compareParameter);
                else
                    (module_it->second)->getStepperSettings(_compareParameter);
                (module_it->second)->getEncoderSettings(_compareParameter);

                if ((module_it->second)->configParameterUploadRequired())
                {
                    I_LOG("Upload config file settings.")
                    (module_it->second)->setBasicSettings();
                    (module_it->second)->setMotorSettings();
                    if ((module_it->second)->getMotorType()
                            == Basda::MotorType::SERVO)
                        (module_it->second)->setServoLoopSettings();
                    else
                        (module_it->second)->setStepperSettings();
                    (module_it->second)->setEncoderSettings();
		    (module_it->second)->initializeMotor();
                }
                (module_it->second)->validateBasicSettings();

                (module_it->second)->getAmplifierCardInfo();
                (module_it->second)->getActivityStatus();
                (module_it->second)->getSignalStatus();
                (module_it->second)->getMotorControllerVersion();
                (module_it->second)->getMotorControllerErrorNr();
            }

            catch (::Nice::Chat::TimeOutException &e)
            {
                std::string errorMsg =
                        "Couln't download settings parameter of motor "
                                + module_it->first + " (" + children_it->first
                                + ") of device " + m_config->name()
                                + ". Call method dumpStatusInformation() manually!";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
            }

            catch (::Basda::MoCon::ParamMissingException &e)
            {
                std::string errorMsg =
                        "Couln't download settings parameter of motor "
                                + module_it->first + " (" + children_it->first
                                + ") of device " + m_config->name()
                                + ". Call method dumpStatusInformation() manually!";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
            }
//            catch (::Basda::MoCon::CmdForAEncException &e)
//            {
//                std::string errorMsg = "Couln't download settings parameter of motor " + module_it->first + " (" + children_it->first + ") of device " + m_config->name() + ". Call method dumpStatusInformation() manually!";
//                E_THROW(::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
//            }
//
//            catch (::Basda::MoCon::CmdForIEncException &e)
//            {
//                std::string errorMsg = "Couln't download settings parameter of motor " + module_it->first + " (" + children_it->first + ") of device " + m_config->name() + ". Call method dumpStatusInformation() manually!";
//                E_THROW(::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
//            }

            catch (::Basda::MoCon::IEncNotInitializedException &e)
            {
                std::string errorMsg =
                        "Couln't download settings parameter of motor "
                                + module_it->first + " (" + children_it->first
                                + ") of device " + m_config->name()
                                + ". Call method dumpStatusInformation() manually!";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
            }

            catch (::Basda::MoCon::MotorNotInitializedException &e)
            {
                std::string errorMsg =
                        "Couln't download settings parameter of motor "
                                + module_it->first + " (" + children_it->first
                                + ") of device " + m_config->name()
                                + ". Call method dumpStatusInformation() manually!";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
            }

            catch (::Basda::MoCon::CmdForServoException &e)
            {
                std::string errorMsg = "The motor " + module_it->first + " ("
                        + children_it->first + ") of device " + m_config->name()
                        + " is a stepper. The motor is configured as servo. "
                                "Check your configuration file.";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
            }

            catch (::Basda::MoCon::CmdForStepperException &e)
            {
                std::string errorMsg = "The motor " + module_it->first + " ("
                        + children_it->first + ") of device " + m_config->name()
                        + " is a servo. The motor is configured as stepper. "
                                "Check your configuration file.";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
            }

            catch (::Basda::MoCon::AADException &e)
            {
                std::string errorMsg =
                        "Couldn't download settings parameter of the amplifier card of motor "
                                + module_it->first + " (" + children_it->first
                                + ") of device " + m_config->name()
                                + ". Call method dumpStatusInformation() manually!";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
            }

            catch (::Basda::MoCon::MotorOffException &e)
            {
                std::string errorMsg = "The motor " + module_it->first + " ("
                        + children_it->first + ") of device " + m_config->name()
                        + " is off. Please follow the described instruction.";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
            }

            catch (::Basda::MoCon::OutOfRangeException &e)
            {
                std::string errorMsg = "The travelrange of motor "  + module_it->first + " ("
                        + children_it->first + ") of device " + m_config->name()
                        + " is not valid. Please check your device config file. "
                        "Validate the travelrange and the properties " +
                        Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsValue() + " and " +
                        Basda::Mocca::MoCon::cfgDatasheetStepperMicrostepsAdaption() + "!";
                F_THROW(Nice::Exception, e, errorMsg)
//                F_THROW(::Basda::MoCon::DumpStatusInformationException, e, errorMsg)
            }

            try
            {
                (module_it->second)->getCurrentTime();
                (module_it->second)->getAmplifierInfo();
            }

            catch (::Nice::Chat::TimeOutException &e)
            {
                std::string errorMsg =
                        "Couln't download settings parameter of motor "
                                + module_it->first + " (" + children_it->first
                                + ") of device " + m_config->name()
                                + ". Call method dumpStatusInformation() manually!";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
            }

            catch (::Basda::MoCon::AmplifierPowerSupplyException &e)
            {
                std::string errorMsg =
                        "The amplifier power supply of motor "
                                + module_it->first + " (" + children_it->first
                                + ") of device " + m_config->name()
                                + " is broken. Call method dumpStatusInformation() manually!";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg)
            }

            catch (::Basda::MoCon::AmplifierFuseException &e)
            {
                std::string errorMsg =
                        "The amplifier fuse of motor " + module_it->first + " ("
                                + children_it->first + ") of device "
                                + m_config->name()
                                + " is broken. Call method dumpStatusInformation() manually!";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg)
            }

            catch (::Basda::MoCon::AmplifierThermalException &e)
            {
                std::string errorMsg =
                        "Critical temperature in amplifier of motor "
                                + module_it->first + " (" + children_it->first
                                + ") of device " + m_config->name()
                                + ". Call method dumpStatusInformation() manually!";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg)
            }

            catch (::Basda::MoCon::AmplifierShortCurrentException &e)
            {
                std::string errorMsg =
                        "Amplifier of motor " + module_it->first + " ("
                                + children_it->first + ") of device "
                                + m_config->name()
                                + " has a short current. "
                                        "Call method dumpStatusInformation() manually!";
                m_completion.setError(errorMsg, e);
                E_THROW( ::Basda::MoCon::DumpStatusInformationException, e, errorMsg)
            }

            D_LOG( "module " << module_it->first << " (" << children_it->first << ") is up to date");
            module_it++;
        }
        children_it++;
    }
    _async.asyncStatus(Basda::Command::Action::DUMPSTATUSINFORMATION, percentTotal += percent);
    m_completion.setPercent(percentTotal);

    try
    {
        resetFatalError();
    }

    catch (::Nice::Chat::TimeOutException &e)
    {
        std::string errorMsg = "Timeout while asking for fatal error. "
                "Call method dumpStatusInformation() manually!";
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
    }

    catch (::Basda::MPIA::ModuleIsInUseException &e)
    {
        W_LOG("Couldn't lock card! Couldn't read out Fatal Error Code! "
        "Call method dumpStatusInformation() manually!");
    }

    catch (::Nice::Exception &e)
    {
        std::string errorMsg = "Call method dumpStatusInformation() manually!";
        m_completion.setError(errorMsg, e);
        E_THROW(::Basda::MoCon::DumpStatusInformationException, e, errorMsg);
    }

    _async.asyncStatus(Basda::Command::Action::DUMPSTATUSINFORMATION, 100);

    if ((m_completion.state() == Nice::EXEC) || (m_completion.state() == Nice::BUSY))
        m_completion.setDone();
}

void Basda::MoConNDevice::resetFatalError()
{
    D_LOG("Get fatal error of all motors and reset the error if one occured.")
    std::stringstream ss;
    Nice::SeqString fatalError;
    std::map<std::string, MoConCardPtr>::iterator card_it = m_card.begin();

    unsigned long tmp;
    int errorNo;

    // ask for the fatal error of each motor
    while (card_it != m_card.end())
    {
        D_LOG("get fatal error of card " << card_it->first);
        std::string error = "0";
        (card_it->second)->lockCard();
        error = (card_it->second)->getFatalError();

        ss << error;
        ss >> errorNo >> std::hex >> tmp;

        if (tmp != 0)
        {
            (card_it->second)->resetFatalError();
        }
        (card_it->second)->unlockCard();

        fatalError.push_back(error);
        card_it++;
    }

    // write the vector back in the POSITION property
    m_config->setAtNode<Nice::SeqString>(
            Basda::Mocca::MoCon::varLastFatalError(), fatalError);
}

#if 0
void Basda::MoConNDevice::checkMotionError()
{
    D_LOG("checkMotionError");

    bool motionError = false;
    std::stringstream errorMsg;
    errorMsg << "MoCon motion error on: ";

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();
    while (module_it != m_module.end())
    {
        U1_LOG((module_it->second)->checkMotionError())
        if ((module_it->second)->checkMotionError())
        {
            (module_it->second)->setMotionComplete(true);
            errorMsg << module_it->first << " ";
            motionError = true;
        }
        module_it++;
    }
U3_LOG(motionError)
    if (motionError)
    {
//        stop();
        resetMotionError();
//        try
//        {
//            dumpStatusInformation();
//        }
//
//        catch (::Basda::MoCon::DumpStatusInformationException &e)
//        {
//            errorMsg << "Stopped movement of device "
//                    + m_config->name();
//            m_completion.setError(errorMsg.str(), e);
//            E_THROW(::Basda::MoCon::MotionErrorException, e, errorMsg.str())
//        }
        errorMsg << "Stopped movement of device "
                        + m_config->name();
        ::Basda::MoCon::MotionErrorException e;
        m_completion.setError(errorMsg.str(), e);
        E_THROW(::Basda::MoCon::MotionErrorException, errorMsg.str());
    }
}

void Basda::MoConNDevice::resetMotionError()
{
    D_LOG("resetMotionError");

    std::map<std::string, MoConModulePtr>::iterator module_it = m_module.begin();

    while (module_it != m_module.end())
    {
        (module_it->second)->resetMotionError();
        module_it++;
    }
}

 void
 Basda::MoConNDevice::lockCard(std::string &_commandName)
 {
     Nice::Guard guard (m_mutex);

     // get the command argument property tree
     Nice::JointPtrMap modChildren = m_config->node("CMD." + _commandName + ".MOD")->children();

     std::map<std::string, Nice::JointPtr>::iterator mod_it = modChildren.begin();
     // for each motor controller card
     while ( mod_it != modChildren.end() )
     {
         Nice::JointPtrMap typeChildren = mod_it->second->node("SAMPLE_TYPE")->children();
         std::map<std::string, Nice::JointPtr>::iterator type_it = typeChildren.begin();

         Nice::JointPtrMap moduleChildren = mod_it->second->node("SAMPLE_MODULE")->children();
         std::map<std::string, Nice::JointPtr>::iterator module_it = moduleChildren.begin();

         // for each sample type
         while (type_it != typeChildren.end() )
         {
             // save that module name for that a sample type is chosen
             if (type_it->second->get<int>() > 0)
             {
                 std::string selectedModule = module_it->second->get<std::string>();
                 m_selectedCards.insert(selectedModule);
                 type_it = typeChildren.end();
             }
             else
             {
                 type_it++;
                 module_it++;
             }
         }
         mod_it++;
     }

     if (!m_selectedCards.empty())
     {
         std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
         it = m_module.begin();

         for( std::set<std::string>::const_iterator iter = m_selectedCards.begin(); iter != m_selectedCards.end(); ++iter )
         {
             // search for the module name in the map and lock the corresponding card object
             it = m_module.find(*iter);
             if (it != m_module.end())
             {
                 D_LOG("Lock Card from module " << *iter);
                 ((it->second).cardPtr)->lockCard();
             }
         }
     }
     else
     {
         D_LOG("Nothing selected to trace!");
     }
 }

 void
 Basda::MoConNDevice::unlockCard()
 {
     Nice::Guard guard (m_mutex);

     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
     it = m_module.begin();

     // for each selected cards
     for( std::set<std::string>::const_iterator iter = m_selectedCards.begin(); iter != m_selectedCards.end(); ++iter )
     {
         // search for the module name in the map and unlock the corresponding card object
         it = m_module.find(*iter);
         if (it != m_module.end())
         {
             D_LOG("Unlock Card from module " << *iter);
             ((it->second).cardPtr)->unlockCard();
         }
     }
     m_selectedCards.clear();
     m_selectedModules.clear();
 }

 void
 Basda::MoConNDevice::addTraceCommandProperties(std::string &_command, bool _timeBasedTrace)
 {
     std::map<std::string, std::map<int, std::string> > m_moduleConfig;
     //     m_config->leaf ( "CMD." + _command )->applyAttribute<std::string>("UI", "$INSROOT/share/ui/MoConTraceUI.ui" );
     m_config->leaf ( "CMD." + _command )->applyAttribute<std::string>("CLASS", "BasdaMoConTrace" );
     m_config->leaf ( "CMD." + _command )->applyAttribute<bool>("PINGPONG", false );
     m_config->setAtNode( "CMD." + _command + ".Stop", false);

     if (_timeBasedTrace)
     {
         m_config->setAtNode( "CMD." + _command + ".BLOCK_SIZE", 100);
         m_config->setAtNode( "CMD." + _command + ".ESTIMATED_TIME", Nice::Time(Nice::Time::seconds(0)));
     }

     std::vector< std::string> sampleType;
     sampleType.push_back("None");
     sampleType.push_back("Commanded_Position");
     sampleType.push_back("Commanded_Velocity");
     sampleType.push_back("Commanded_Acceleration");
     sampleType.push_back("Actulal_Position");
     sampleType.push_back("Actual_Velocity");
     sampleType.push_back("Position_Error");
     sampleType.push_back("PID_Error");
     sampleType.push_back("Event_Status_Register");
     sampleType.push_back("Activity_Status_Register");
     sampleType.push_back("Signal_Status_Register");
     sampleType.push_back("Integral");
     sampleType.push_back("Derivative");
     sampleType.push_back("Motor_Command");
     sampleType.push_back("Capture_Register");
     sampleType.push_back("Chipset_Time");

     std::vector< std::string> sampleMode;
     sampleMode.push_back("One_Time");
     sampleMode.push_back("Rolling_Buffer");

     Nice::JointPtrMap modChildren = m_config->node("MOD")->children();
     std::map<std::string, Nice::JointPtr>::iterator mod_it = modChildren.begin();
     while ( mod_it != modChildren.end() )
     {
         std::string address = (mod_it->second)->getAtNode<std::string>(Basda::Mocca::MoCon::cfgConnectionAddress());

         // extract the connection string
         std::string::size_type idx_type = address.find (':');
         std::string type = address.substr (0, idx_type);
         std::string connection;
         if (type == "tcp")
         {
             std::string::size_type idx_con = address.substr (idx_type + 3).find (':');
             connection = address.substr (idx_type + 3, idx_con);
             std::string::size_type found = connection.find_first_of(".");

             while( found != std::string::npos )
             {
                 connection[found] = '-';
                 found = connection.find_first_of(".",found+1);
             }
         }
         else if (type == "tty")
         {
             std::string::size_type idx_con = address.substr (idx_type + 1).find (':');
             connection = address.substr (idx_type + 1, idx_con);
         }
         // create card ID, which consist of the connection string and the card number
         std::string cardID = std::string("MOD." + connection + ":" + (mod_it->second)->getAtNode<std::string>(Basda::Mocca::MoCon::cfgConnectionCard()));
         int module = (mod_it->second)->getAtNode<int>(Basda::Mocca::MoCon::cfgConnectionModule());

         // create a map that group the module numbers with the module name to the corresponding cardID
         //        cardID                 module number, module name
         std::map< std::string, std::map< int, std::string> >::iterator mod_jt = m_moduleConfig.find(cardID);
         // if the cardID is not in the m_moduleConfig map than insert the module number and the module name with the corresponding cardID
         if (mod_jt == m_moduleConfig.end())
         {
             std::map<int, std::string> modules;
             modules.insert( std::make_pair(module, mod_it->first) );
             m_moduleConfig.insert( std::make_pair(cardID, modules) );
         }
         // otherwise just insert the module number and module name
         else
         {
             (mod_jt->second).insert(std::make_pair(module, mod_it->first) );
         }
         mod_it++;
     }

     std::map< std::string, std::map< int, std::string> >::iterator mod_jt = m_moduleConfig.begin();
     // for each cardID create a card GUI
     while (mod_jt != m_moduleConfig.end())
     {
         m_config->node("CMD." + _command + "." + mod_jt->first +".SAMPLE_RATE")->set<Ice::Int>( m_config->node("MOD." + (mod_jt->second).begin()->second + ".CFG.DATASHEET.TRACE.SAMPLE_RATE")->get<Ice::Int>() );
         m_config->leaf("CMD." + _command + "." + mod_jt->first +".SAMPLE_RATE")->applyAttribute<Ice::Int>("MIN", m_config->leaf( "MOD." + (mod_jt->second).begin()->second + ".CFG.DATASHEET.TRACE.SAMPLE_RATE")->attribute("MIN")->get<Ice::Int>() );
         m_config->leaf("CMD." + _command + "." + mod_jt->first +".SAMPLE_RATE")->applyAttribute<Ice::Int>("MAX", m_config->leaf( "MOD." + (mod_jt->second).begin()->second + ".CFG.DATASHEET.TRACE.SAMPLE_RATE")->attribute("MAX")->get<Ice::Int>() );
         m_config->leaf("CMD." + _command + "." + mod_jt->first +".SAMPLE_RATE")->applyActor(new Nice::PropertyActorMinMax<Ice::Int>());

         if (_timeBasedTrace)
         {
             m_config->node("CMD." + _command + "." + mod_jt->first +".NoS"       )->set<Ice::Int>( m_config->node("MOD." + (mod_jt->second).begin()->second + ".CFG.DATASHEET.TRACE.NUMBER_OF_SAMPLES")->get<Ice::Int>() );
             m_config->leaf("CMD." + _command + "." + mod_jt->first +".NoS"       )->applyAttribute<Ice::Int>("MIN", m_config->leaf( "MOD." + (mod_jt->second).begin()->second + ".CFG.DATASHEET.TRACE.NUMBER_OF_SAMPLES" )->attribute("MIN")->get<Ice::Int>() );
             m_config->leaf("CMD." + _command + "." + mod_jt->first +".NoS"       )->applyAttribute<Ice::Int>("MAX", m_config->leaf( "MOD." + (mod_jt->second).begin()->second + ".CFG.DATASHEET.TRACE.NUMBER_OF_SAMPLES" )->attribute("MAX")->get<Ice::Int>() );
             m_config->leaf("CMD." + _command + "." + mod_jt->first +".NoS"       )->applyActor(new Nice::PropertyActorMinMax<Ice::Int>());

             m_config->node("CMD." + _command + "." + mod_jt->first +".SAMPLE_MODE")->set<Ice::Int>( m_config->node("MOD." + (mod_jt->second).begin()->second + ".CFG.DATASHEET.TRACE.SAMPLE_MODE")->get<Ice::Int>() );
             m_config->leaf("CMD." + _command + "." + mod_jt->first +".SAMPLE_MODE")->applyAttribute<std::vector<std::string> >("SELECT", sampleMode);
         }
         std::map<int, std::string>::iterator start14 = (mod_jt->second).begin();
         std::map<int, std::string>::iterator end14 = (mod_jt->second).upper_bound(4);
         std::map<int, std::string>::iterator start58 = (mod_jt->second).lower_bound(5);;

         std::vector< std::string> modules14;
         std::vector< std::string> modules58;

         for ( ; start14 != end14; start14++)
             modules14.push_back(start14->second);
         for ( ; (start58 != (mod_jt->second).end()); start58++)
             modules58.push_back(start58->second);

         if (!modules14.empty())
         {
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.1", modules14.at(0));
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.2", modules14.at(0));
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.3", modules14.at(0));
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.4", modules14.at(0));

             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.1",  0);
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.2",  0);
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.3",  0);
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.4",  0);

             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.1" )->applyAttribute<std::vector<std::string> >("SELECT", modules14 );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.2" )->applyAttribute<std::vector<std::string> >("SELECT", modules14 );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.3" )->applyAttribute<std::vector<std::string> >("SELECT", modules14 );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.4" )->applyAttribute<std::vector<std::string> >("SELECT", modules14 );

             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.1" )->applyAttribute<std::vector<std::string> >("SELECT", sampleType );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.2" )->applyAttribute<std::vector<std::string> >("SELECT", sampleType );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.3" )->applyAttribute<std::vector<std::string> >("SELECT", sampleType );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.4" )->applyAttribute<std::vector<std::string> >("SELECT", sampleType );
         }
         if (!modules58.empty())
         {
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.5", modules58.at(0));
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.6", modules58.at(0));
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.7", modules58.at(0));
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.8", modules58.at(0));

             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.5",  0);
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.6",  0);
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.7",  0);
             m_config->setAtNode( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.8",  0);

             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.5" )->applyAttribute<std::vector<std::string> >("SELECT", modules58 );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.6" )->applyAttribute<std::vector<std::string> >("SELECT", modules58 );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.7" )->applyAttribute<std::vector<std::string> >("SELECT", modules58 );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_MODULE.8" )->applyAttribute<std::vector<std::string> >("SELECT", modules58 );

             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.5" )->applyAttribute<std::vector<std::string> >("SELECT", sampleType );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.6" )->applyAttribute<std::vector<std::string> >("SELECT", sampleType );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.7" )->applyAttribute<std::vector<std::string> >("SELECT", sampleType );
             m_config->leaf ( "CMD." + _command + "." + mod_jt->first +".SAMPLE_TYPE.8" )->applyAttribute<std::vector<std::string> >("SELECT", sampleType );
         }

         mod_jt++;
     }
 }

 int
 Basda::MoConNDevice::configureTimeBasedTrace()
 {
     Nice::Guard guard (m_mutex);

     bool rollingBuffer = false;
     int numberOfSamples = 0;
     int tmp = 0;

     // get the command argument property tree
     Nice::JointPtrMap modChildren = m_config->node("CMD.traceTimeBased.MOD")->children();

     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
     it = m_module.begin();

     // get the first motor controller card
     std::map<std::string, Nice::JointPtr>::iterator mod_it = modChildren.begin();
     // for each motor controller card
     while ( mod_it != modChildren.end() )
     {
         int sampleRate = mod_it->second->node("SAMPLE_RATE")->get<Ice::Int>();
         rollingBuffer |= mod_it->second->node("SAMPLE_MODE")->get<Ice::Int>();
         bool cardConfigured = false;
 //         int buffer = 1;

         Nice::JointPtrMap typeChildren = mod_it->second->node("SAMPLE_TYPE")->children();
         std::map<std::string, Nice::JointPtr>::iterator type_it = typeChildren.begin();

         Nice::JointPtrMap moduleChildren = mod_it->second->node("SAMPLE_MODULE")->children();
         std::map<std::string, Nice::JointPtr>::iterator module_it = moduleChildren.begin();

         // for each sample type
         while (type_it != typeChildren.end() )
         {
             // only if a sample type is choosen
             if (type_it->second->get<int>() > 0)
             {
                 // save that module name for that a sample type is choosen
                 std::string selectedModule = module_it->second->get<std::string>();
                 m_selectedModules.insert(selectedModule);
                 it = m_module.find(selectedModule);

                 if (it != m_module.end())
                 {
                     // configure the card only once
                     if (!cardConfigured)
                     {
                         ((it->second).cardPtr)->setTimeTraceSampleRate(sampleRate);
                         tmp = mod_it->second->node("NoS")->get<Ice::Int>();
                         ((it->second).cardPtr)->setTimeTraceNumberOfSamples(tmp ); //m_config->node("MOD." + selectedModule),
                         ((it->second).cardPtr)->setTimeTraceSampleMode((Basda::ValueTraceSampleMode)mod_it->second->node("SAMPLE_MODE")->get<Ice::Int>());
                         cardConfigured = true;
                     }

                     ((it->second).modulePtr)->setTimeBasedTraceSampleRate(sampleRate);
          std::stringstream ss;
          ss << type_it->first;
          unsigned int buffer;
          ss >> buffer;
                     ((it->second).modulePtr)->setTimeBasedTraceType(buffer, (Basda::ValueTraceType)type_it->second->get<int>());
                 }
             }
             if (tmp > numberOfSamples)
                 numberOfSamples = tmp;
             type_it++;
             module_it++;
         }
         mod_it++;
     }

     return numberOfSamples;
 }

 bool
 Basda::MoConNDevice::getTimeBasedRollingBuffer()
 {
     Nice::Guard guard (m_mutex);

     bool rollingBuffer = false;

     Nice::JointPtrMap modChildren = m_config->node("CMD.traceTimeBased.MOD")->children();
     std::map<std::string, Nice::JointPtr>::iterator mod_it = modChildren.begin();

     while ( mod_it != modChildren.end() )
     {
         // set the rolling buffer to true if one of the card uses the rolling buffer mode
         rollingBuffer |= mod_it->second->node("SAMPLE_MODE")->get<Ice::Int>();
         mod_it++;
     }

     return rollingBuffer;
 }

 void
 Basda::MoConNDevice::getReferenceTime( const Nice::Completion &_c )
 {
     Nice::Guard guard (m_mutex);
     D_LOG("MoConNDevice::getReferenceTime");
     Nice::PropertyPtr synchronizeTimePtr = m_config->node( "CMD.getReferenceTime" )->leaf();
     synchronizeTimePtr->change<Nice::Completion,std::string>(& Nice::Completion::start, "synchronizeTime", (Nice::I64)0);
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it = m_module.begin();
     std::vector<std::string> v;
     while ( it != m_module.end() )
     {
         v.push_back( it->first );
         it++;
     }
     getReferenceTime(v);
     synchronizeTimePtr->change<Nice::Completion>(& Nice::Completion::setDone, (Nice::I64)0);
 }

 void
 Basda::MoConNDevice::getCurrentTime( const Nice::Completion &_c )
 {
     D_LOG("MoConNDevice::getCurrentTime");
     Nice::Completion c;

     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it = m_module.begin();
     std::vector<std::string> v;
     while ( it != m_module.end() )
     {
         v.push_back( it->first );
         it++;
     }
     getCurrentTime(v);
     c.setDone();
     m_config->node( "CMD.getCurrentTime" )->leaf()->set<Nice::Completion>( c, 0 );
 }

 void
 Basda::MoConNDevice::timeBasedTraceStart()
 {
     Nice::Guard guard (m_mutex);

     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
     it = m_module.begin();

     // start the trace at every necessary card
     for( std::set<std::string>::const_iterator iter = m_selectedCards.begin(); iter != m_selectedCards.end(); ++iter )
     {
         it = m_module.find(*iter);
         if (it != m_module.end())
         {
             D_LOG("Start time based trace on card from module " << *iter);
             ((it->second).cardPtr)->timeTraceStart();
         }
     }
 }

 void
 Basda::MoConNDevice::timeBasedTraceStop()
 {
     Nice::Guard guard (m_mutex);

     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
     it = m_module.begin();

     for( std::set<std::string>::const_iterator iter = m_selectedCards.begin(); iter != m_selectedCards.end(); ++iter )
     {
         it = m_module.find(*iter);
         if (it != m_module.end())
         {
             D_LOG("Stop time based trace on card from module " << *iter);
             ((it->second).cardPtr)->timeTraceStop();
         }
     }
 }

 void
 Basda::MoConNDevice::clearTimeBasedTraceBuffer()
 {
     Nice::Guard guard (m_mutex);

     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
     it = m_module.begin();

     for( std::set<std::string>::const_iterator iter = m_selectedCards.begin(); iter != m_selectedCards.end(); ++iter )
     {
         it = m_module.find(*iter);
         if (it != m_module.end())
         {
             D_LOG("Clear trace buffer on card from module " << *iter);
             ((it->second).cardPtr)->clearTimeTraceBuffer();
         }
     }
 }

 void
 Basda::MoConNDevice::getTimeBasedTraceData(Nice::Completion &_completion)
 {
     Nice::Guard guard (m_mutex);

     std::string action("Receiving Data...");
     int selectedModules = m_selectedModules.size();
     double tracePercent = _completion.percent();
     double readPercent = (100 - tracePercent) / selectedModules;
     int readCycles;
     int blockSize = m_config->node( "CMD.traceTimeBased.BLOCK_SIZE")->get<Ice::Int>();
     int i = 0;

     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
     it = m_module.begin();

     // receive the traced data module by module
     for( std::set<std::string>::const_iterator iter = m_selectedModules.begin(); iter != m_selectedModules.end(); ++iter, i++ )
     {
         // find the module by its name
         it = m_module.find(*iter);
         if (it != m_module.end())
         {
             // get the number of traced values
             getTraceInfo();
             int traceValues = m_config->node( "MOD." + *iter + ".VAR.TRACE.INFO.TRACED_VALUES")->get<int>();
             D_LOG("traced " << traceValues << " values");
             readCycles = traceValues / blockSize;

             // send the command to get the traced data
             D_LOG("Get trace data from module " << *iter);
             ((it->second).modulePtr)->getTimeBasedTraceData(traceValues, 1);

             // receive the traced data block by block
             for(int j = 1; j < readCycles; j++)
             {
                 D_LOG("read " << j << " " << (j-1)*blockSize + 1 << " - " << (j) * blockSize);
                 ((it->second).modulePtr)->receiveTimeBasedTraceData(blockSize);
                 _completion.setAction(j * readPercent / readCycles + tracePercent + i * readPercent, action);
                 m_config->node( "CMD.traceTimeBased" )->leaf()->set<Nice::Completion>( _completion, 0 );
                 _completion.setPercent(100);
                 m_config->node( "CMD.traceTimeBased" )->leaf()->set<Nice::Completion>( _completion, 0 );
                 break;
             }

             D_LOG("read last values");
             ((it->second).modulePtr)->receiveTimeBasedTraceData(-1);
         }
     }
 }

 void
 Basda::MoConNDevice::configureEventBasedTrace()
 {
     Nice::Guard guard (m_mutex);

     // get the command argument property tree
     Nice::JointPtrMap modChildren = m_config->node("CMD.traceEventBased.MOD")->children();

     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
     it = m_module.begin();

     // get the first motor controller card
     std::map<std::string, Nice::JointPtr>::iterator mod_it = modChildren.begin();
     // for each motor controller card
     while ( mod_it != modChildren.end() )
     {
         int sampleRate = mod_it->second->node("SAMPLE_RATE")->get<Ice::Int>();
         bool cardConfigured = false;
         int buffer = 1;

         Nice::JointPtrMap typeChildren = mod_it->second->node("SAMPLE_TYPE")->children();
         std::map<std::string, Nice::JointPtr>::iterator type_it = typeChildren.begin();

         Nice::JointPtrMap moduleChildren = mod_it->second->node("SAMPLE_MODULE")->children();
         std::map<std::string, Nice::JointPtr>::iterator module_it = moduleChildren.begin();

         // for each sample type
         while (type_it != typeChildren.end() )
         {
             // only if a sample type is choosen
             if (type_it->second->get<int>() > 0)
             {
                 // save that module name for that a sample type is choosen
                 std::string selectedModule = module_it->second->get<std::string>();
                 m_selectedModules.insert(selectedModule);
                 it = m_module.find(selectedModule);

                 if (it != m_module.end())
                 {
                     // configure the card only once
                     if (!cardConfigured)
                     {
                         ((it->second).cardPtr)->setEventTraceSampleRate(sampleRate);
                         cardConfigured = true;
                     }

                     ((it->second).modulePtr)->setTimeBasedTraceSampleRate(sampleRate);
                     ((it->second).modulePtr)->setEventBasedTraceType(buffer++, (Basda::ValueTraceType)type_it->second->get<int>());
                 }
             }
             type_it++;
             module_it++;
         }
         mod_it++;
     }
 }

 void
 Basda::MoConNDevice::eventBasedTraceStart()
 {
     Nice::Guard guard (m_mutex);

     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
     it = m_module.begin();

     for( std::set<std::string>::const_iterator iter = m_selectedCards.begin(); iter != m_selectedCards.end(); ++iter )
     {
         it = m_module.find(*iter);
         if (it != m_module.end())
         {
             D_LOG("Start event trace on card from module " << *iter);
             ((it->second).cardPtr)->eventTraceStart();
         }
     }
 }

 void
 Basda::MoConNDevice::eventBasedTraceStop()
 {
     Nice::Guard guard (m_mutex);

     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
     it = m_module.begin();

     // start the trace at every necessary card
     for( std::set<std::string>::const_iterator iter = m_selectedCards.begin(); iter != m_selectedCards.end(); ++iter )
     {
         it = m_module.find(*iter);
         if (it != m_module.end())
         {
             D_LOG("Stop trace on card from module " << *iter);
             ((it->second).cardPtr)->eventTraceStop();
         }
     }
 }

 int
 Basda::MoConNDevice::getTraceInfo()
 {
     Nice::Guard guard (m_mutex);

     bool tracing = false;
     int tracedValues = 0;
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator it;
     it = m_module.begin();

     // return the trace info for every used module
     for( std::set<std::string>::const_iterator iter = m_selectedModules.begin(); iter != m_selectedModules.end(); ++iter )
     {
         it = m_module.find(*iter);
         if (it != m_module.end())
         {
             D_LOG("getTraceInfo from card of module " << *iter);
             ((it->second).cardPtr)->getTraceInfo(m_config->node( "MOD." + *iter));
             tracing |= m_config->node( "MOD." + *iter + ".VAR.TRACE.INFO.TRACING")->get<bool>();
             int tmp = m_config->node( "MOD." + *iter + ".VAR.TRACE.INFO.TRACED_VALUES")->get<int>();
             if (tmp > tracedValues)
                 tracedValues = tmp;
         }
     }
     m_config->setAtNode<bool>( "VAR.TRACE.INFO.TRACING", tracing );
     m_config->setAtNode<int>( "VAR.TRACE.INFO.TRACED_VALUES", tracedValues );
     return tracedValues;
 }

 void
 Basda::MoConNDevice::waitForEvent()
 {
     D_LOG("waitForEvent");
 //     m_xCardPtr->waitForEvent();
 }

 void
 Basda::MoConNDevice::convertTrajectoryToProfile(std::map<std::string, std::vector<double> > _positionsSequences)
 {
     D_LOG("convertTrajectoryToProfile");
     std::map<std::string, std::vector<double> >::iterator it;
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator jt;

     // each motor in the argument map have to move to the absolute position
     for( it = _positionsSequences.begin(); it != _positionsSequences.end(); it++ )
     {
         // search for the given motor name in the map
         jt = m_module.find( it->first );
         if( jt != m_module.end() )
         {
             D_LOG(it->first << " convert trajectory to profile ");
             double timeResolution = m_config->node ( "CMD.externalProfile.MOD." + it->first + ".TIME_RESOLUTION")->get<double>();
             unsigned int samplesPerSegment = m_config->node ( "CMD.externalProfile.MOD." + it->first + ".SAMPLES_PER_SEGMENT")->get< unsigned int >();
             unsigned int maxError = m_config->leaf ( "CMD.externalProfile.MOD." + it->first + ".MAX_ERROR")->get< unsigned int >();
             ((jt->second).modulePtr)->convertTrajectoryToProfile( it->second, timeResolution, samplesPerSegment, maxError );
         }
     }
 }

 void
 Basda::MoConNDevice::setExternalProfileStop(std::vector<std::string> _externalProfileModules)
 {
     D_LOG("setExternalProfileStop");
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator jt;

     for (unsigned int i = 0; i < _externalProfileModules.size(); i++)
     {
         jt = m_module.find( _externalProfileModules.at(i) );
         if( jt != m_module.end() )
         {
             ((jt->second).modulePtr)->setExternalProfileStop();
         }
     }
 }

 void
 Basda::MoConNDevice::setExternalProfileStart(std::map<std::string, Nice::I64> _externalProfileModules)
 {
     D_LOG("setExternalProfileStart");
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator jt;

     for (std::map<std::string, Nice::I64>::iterator it = _externalProfileModules.begin(); it != _externalProfileModules.end(); it++)
     {
         jt = m_module.find( it->first );
         if( jt != m_module.end() )
         {
             if (it->second == -1)
                 ((jt->second).modulePtr)->setExternalProfileStart(MOCON_MODE_START_FROM_BEGINNING);
             else
                 ((jt->second).modulePtr)->setExternalProfileTimeStart((unsigned int)it->second, MOCON_MODE_START_FROM_BEGINNING);
         }
     }
 }

 void
 Basda::MoConNDevice::clearExternalProfileBuffer(std::vector<std::string> _externalProfileModules)
 {
     D_LOG("clearExternalProfileBuffer");
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator jt;

     for (unsigned int i = 0; i < _externalProfileModules.size(); i++)
     {
         jt = m_module.find( _externalProfileModules.at(i) );
         if( jt != m_module.end() )
         {
             ((jt->second).modulePtr)->clearExternalProfileBuffer();
         }
     }
 }

 void
 Basda::MoConNDevice::tryClearExternalProfileBuffer(std::vector<std::string> _externalProfileModules)
 {
     D_LOG("tryClearExternalProfileBuffer");
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator jt;

     for (unsigned int i = 0; i < _externalProfileModules.size(); i++)
     {
         jt = m_module.find( _externalProfileModules.at(i) );
         if( jt != m_module.end() )
         {
             ((jt->second).modulePtr)->tryClearExternalProfileBuffer();
         }
     }
 }

 void
 Basda::MoConNDevice::uploadExternalProfile(std::vector<std::string> _externalProfileModules)
 {
     D_LOG("uploadExternalProfile");
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator jt;

     for (unsigned int i = 0; i < _externalProfileModules.size(); i++)
     {
         jt = m_module.find( _externalProfileModules.at(i) );
         if( jt != m_module.end() )
         {
             ((jt->second).modulePtr)->uploadExternalProfile();
         }
     }
 }

 unsigned int
 Basda::MoConNDevice::getExternalProfileSize(std::vector<std::string> _externalProfileModules)
 {
     D_LOG("getExternalProfileSize");
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator jt;
     unsigned int tmp = 0;
     unsigned int maxProfileSize = 0;

     for (unsigned int i = 0; i < _externalProfileModules.size(); i++)
     {
         jt = m_module.find( _externalProfileModules.at(i) );
         if( jt != m_module.end() )
         {
             tmp = ((jt->second).modulePtr)->getExternalProfileSize();
             if (tmp > maxProfileSize)
                 maxProfileSize = tmp;
         }
     }
     return maxProfileSize;
 }

 unsigned int
 Basda::MoConNDevice::getExternalProfileInfo(std::vector<std::string> _externalProfileModules)
 {
     D_LOG("getExternalProfileInfo");
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator jt;
     unsigned int tmp = 0;
     unsigned int maxProfileIndex = 0;

     for (unsigned int i = 0; i < _externalProfileModules.size(); i++)
     {
         jt = m_module.find( _externalProfileModules.at(i) );
         if( jt != m_module.end() )
         {
             tmp = ((jt->second).modulePtr)->getExternalProfileInfo();
             if (tmp < maxProfileIndex)
                 maxProfileIndex = tmp;
         }
     }
     return maxProfileIndex;
 }

 void
 Basda::MoConNDevice::unitChanged(const Nice::Any &_a)
 {
 //    m_moveAbsThread->unitChanged();
 //    m_moveRelThread->unitChanged();
     m_currentUnit = m_config->node( "VAR.UNIT" )->get<int>();
     getPosition();
 }

 std::map<std::string, double>
 Basda::MoConNDevice::convertUnit(std::map<std::string, double> _modules)
 {
     std::map<std::string, double>::iterator it;
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator jt;
     Unit unit = (Unit)m_config->node( "VAR.UNIT" )->get<int>();

     for (std::map<std::string, double>::iterator it = _modules.begin(); it != _modules.end(); it++)
     {
         jt = m_module.find( it->first );
         if( jt != m_module.end() )
         {
             it->second = ( (jt->second).modulePtr)->convertToLength( ( (jt->second).modulePtr)->convertToSteps( it->second , (Unit)m_currentUnit ), unit );
         }
     }
     return _modules;
 }

 void
 Basda::MoConNDevice::terminal(const Nice::Completion & _c)
 {
 //     Nice::Guard guard (m_mutex);
     Nice::Completion c = _c;
     Nice::Terminal t;
     std::stringstream ss;
     std::string module;
     unsigned int cardNo;
     unsigned int commandID;
     unsigned int moduleNo;
     std::string parameter;
     std::string ret;

     std::map<unsigned int, unsigned int>::iterator it;
     std::map<std::string, Basda::MoConNDevice::Modules>::iterator jt;

     if (_c.state() == Nice::EXEC)
     {
         if (m_config->node("CMD.terminal")->leaf()->attribute("ADVANCED")->get<bool>())
         {
             c.start(c.action());
 //             m_config->node("CMD.terminal")->set<Nice::Completion> ( c, Nice::Date::now() );
 //             Nice::Terminal t = m_config->node("CMD.terminal")->leaf()->attribute("DATA_PACKAGE")->get<Nice::Terminal>();
             std::stringstream ss;
             ss << c.action();
             ss >> t;
             if (t.type() == Nice::OUTGOING)
             {
                 ss << t.command();
                 ss >> module >> commandID;
                 std::getline(ss, parameter);

                 // search for the given motor name in the map
                 jt = m_module.find( module );
                 if( jt != m_module.end() )
                 {
                     cardNo   = (unsigned int)m_config->getAtNode<int>(std::string("MOD.") + module + std::string(".CFG.CONNECTION.CARD") );
                     moduleNo = (unsigned int)m_config->getAtNode<int>(std::string("MOD.") + module + std::string(".CFG.CONNECTION.MODULE") );

                     it = m_cardCmd.find(commandID);
                     if ( it != m_cardCmd.end() )
                     {
                         ((jt->second).cardPtr)->lockCard();
                         ((jt->second).cardPtr)->terminal(commandID, cardNo, 0, ret, parameter);
                         ((jt->second).cardPtr)->unlockCard();
                     }
                     else
                         ((jt->second).cardPtr)->terminal(commandID, cardNo, moduleNo, ret, parameter);

                     parse(module, ret, c);
                 }
                 else
                 {
                     ss << module << " " << commandID << " " << parameter;
                     t.setType(Nice::INCOMING);
                     t.setLevel(Nice::TERROR);
                     t.setCommand(ss.str());
                     t.setComment(std::string("Module ") + module + std::string(" not defined. The module name replaces the MoCon CardNo and MoCon MotoNo. Usage: module_name mocon_cmd [mocon_parameter] Example: X 124 1000"));
                     ss.clear();
                     ss << t;
                     c.setAction(100, ss.str());
                     U6_LOG(t)
                 }
             }
         }
         else
         {
             W_LOG("Advanced mode is not enabled!")
         }
     }
 }

 void
 Basda::MoConNDevice::parse(std::string _module, std::string _ret, Nice::Completion _c)
 {
     std::stringstream returnAll;
     std::stringstream returnTmp;
     std::stringstream event;
     std::stringstream functionError;
     std::string returnLine;
     std::string parameter;
     int cardNo, cmdID, moduleNo, typeID;
     Nice::Terminal t;

     Nice::PropertyPtr terminalPtr = m_config->node("CMD.terminal")->leaf();
     returnAll << _ret;
     while( std::getline(returnAll, returnLine) )
     {
         returnTmp.clear();
         returnTmp << returnLine;
         returnTmp >> cardNo >>  cmdID >>  moduleNo >>  typeID >> std::ws; // extract the data

         parameter = "";
         std::getline(returnTmp, parameter);
         returnTmp.clear();
         returnTmp << _module << " " << cardNo << " " << cmdID << " " << moduleNo << " " << typeID << " " << parameter << std::endl;
         std::getline(returnTmp, returnLine);

         t.setType(Nice::INCOMING);

         switch (typeID)
         {
             case COMMAND_OK_MSG:
                     t.setLevel(Nice::TOK);
                     t.setCommand(returnLine);
                     t.setComment("Command acknowledge");
                     break;
             case DATA_MSG:
                     t.setLevel(Nice::TINFO);
                     t.setCommand(returnLine);
                     t.setComment("Data message");
                     break;
             case EVENT_MSG:
                     t.setLevel(Nice::TEVENT);
                     t.setCommand(returnLine);
                     unsigned int eventNo;
                     event << parameter;
                     event >> eventNo;

                     if (moduleNo) // function error handling for modules
                     {
                         switch (eventNo)
                         {
                             case EVENT__MSG_MOTION_COMPLETE:  t.setComment("Motion complete.");            break;
                             case EVENT__MSG_IN_POS_LIMIT:     t.setComment("Motor is in positive limit."); break;
                             case EVENT__MSG_IN_NEG_LIMIT:     t.setComment("Motor is in negative limit."); break;
                             case EVENT__MSG_MOTION_ERROR:     t.setComment("Motion error.");               break;
                             case EVENT__MSG_EVENT_TRACE_DATA: t.setComment("Trace Data.");                 break;
                             default: t.setComment("Event message");                                        break;
                         }
                     }
                     else // function error handling for cards
                     {
                         t.setComment("Event message");
                     }
                     break;
             case INFO_MSG:
                     t.setLevel(Nice::TINFO);
                     t.setCommand(returnLine);
                     t.setComment("Info message");
                     break;
             case ERR_MSG_CARD_NR:         t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Wrong card number.");         break;
             case ERR_MSG_COMMAND:         t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Wrong command number.");      break;
             case ERR_MSG_MODULE_NR:       t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Wrong module number.");       break;
             case ERR_MSG_PARAMETER:       t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Bad parameter.");             break;
             case ERR_MSG_DOUBLE_ID:       t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Module already registered."); break;
             case ERR_MSG_CMD_B_OVERRUN:   t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Command buffer overflow.");   break;
             case ERR_MSG_CAN_B_OVERRUN:   t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Can bus overflow.");          break;
             case ERR_MSG_SER_B_OVERRUN:   t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Serial bus overflow.");       break;
             case ERR_MSG_RAM_FULL:        t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Memory overflow.");           break;
             case ERR_MSG_FUNCTION_ERR:
                     t.setLevel(Nice::TERROR);
                     t.setCommand(returnLine);
                     unsigned int functionErrorNo;
                     functionError >> functionErrorNo;
                     if (moduleNo) // function error handling for modules
                     {
                         switch (functionErrorNo)
                         {
                             case ERR__COM_WITH_MC:     t.setComment("Checksum error.");                                                       break;
                             case ERR__CMD_FOR_2500:    t.setComment("The method is only for stepper chipset.");                               break;
                             case ERR__CMD_FOR_2800:    t.setComment("The method is only for servo chipset.");                                 break;
                             case ERR__REV_NOT_DEF:     t.setComment("The steps/count per revolution have to be defined first.");              break;
                             case ERR__MOT_IN_MOTION:   t.setComment("Motor is still in motion.");                                             break;
                             case ERR__INIT_BASIS_SET:  t.setComment("Some parameter are missing for the requested profile.");                 break;
                             case ERR__INIT_AAD:        t.setComment("A communication error with the EEPROM at the amplifier card occur.");    break;
                             case ERR__AMP_NA:          t.setComment("No amplifier detected.");                                                break;
                             case ERR__AMP_MC_NC:       t.setComment("Detected amplifier is not compatible with the motor chipset.");          break;
                             case ERR__MICROSTEP_NA:    t.setComment("Amplifier does not support the the current microstep resolution.");      break;
                             case ERR__MOTOR_NOT_INIT:  t.setComment("Motor is not initialized.");                                             break;
                             case ERR__MOTOR_IN_POS_L:  t.setComment("Motor is in positive limit.");                                           break;
                             case ERR__MOTOR_IN_NEG_L:  t.setComment("Motor is in negative limit.");                                           break;
                             case ERR__FIND_HOME_NA:    t.setComment("Motor settings incomplete. Home search is not available.");              break;
                             case ERR__NO_ACCESS_MS:    t.setComment("No access to the motor settings at the EEPROM.");                        break;
                             case ERR__IENC_NOT_INIT:   t.setComment("No incremental encoder initialized.");                                   break;
                             case ERR__INIT_TRACE_SET:  t.setComment("The trace settings is not complete. Some parameter are still missing."); break;
                             case ERR__TRACE_TO_SMALL:  t.setComment("Not enough memory for the given number of samples.");                    break;
                             case ERR__EXTERN_RAM:      t.setComment("External buffer overflow.");                                             break;
                             case ERR__TRACE_BUFFER_OR: t.setComment("Buffer overrun. Data couldn't send fast enough.");                       break;
                             case ERR__TRACE_BUF_NDEF:  t.setComment("Trace buffer is not allocated.");                                        break;
                             case ERR__EP_SIZE_SET:     t.setComment("Buffer already reserved.");                                              break;
                             case ERR__EP_SIZE_NOT_SET: t.setComment("The buffer size is not defined yet.");                                   break;
                             case ERR__INIT_LIMIT_ERR:  t.setComment("Both limits are active.");                                               break;
                             default:                   t.setComment("Function error.");                                                       break;
                         }
                     }
                     else // function error handling for cards
                     {
                         switch (functionErrorNo)
                         {
                             case ERR__COM_WITH_MC:     t.setComment("Checksum error.");                                                       break;
                             case ERR__INIT_TRACE_SET:  t.setComment("The trace settings is not complete. Some parameter are still missing."); break;
                             case ERR__EXTERN_RAM:      t.setComment("The external RAM produce an error.");                                    break;
                             case ERR__TRACE_BUFFER_OR: t.setComment("Trace buffer overrun. Reduce the sample rate");                          break;
                             default:                   t.setComment("Function error.");                                                       break;
                         }
                     }
                     break;
             case ERR_MSG_MAX_NR_CLIENTS:  t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Max clients reached.");       break;
             case ERR_MSG_TEL_PASSWORD:    t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Wrong password.");            break;
             case ERR_MSG_LOGIN_NEEDED:    t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Login needed.");              break;
             case ERR_MSG_USER_DISABLE:    t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("User kicked.");               break;
             case ERR_MSG_PORT_IN_USE:     t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Port is in use.");            break;
             case ERR_MSG_MODULE_IN_USE:   t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Module is in use.");          break;
             case ERR_MSG_NO_MODULE_RES:   t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Module is not reserved.");    break;
             case ERR_MSG_HUGEDATA_IN_USE: t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Huge data is in use.");       break;
             case ERR_MSG_HD_NOT_SUPPORT:  t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Command number does not support huge data transport.");             break;
             case ERR_MSG_FRAG_SIZE_SMALL: t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("Fragment size is to small."); break;
             case ERR_MSG_FATAL_ERROR:     t.setLevel(Nice::TERROR); t.setCommand(returnLine); t.setComment("A fatal error occur.");       break;
             default:
                     t.setLevel(Nice::TERROR);
                     t.setCommand(returnLine);
                     std::stringstream error;
                     error << "Unknown message type #" << typeID;
                     t.setComment(error.str());
                     break;
         }
         std::stringstream ss;
         ss << t;
         _c.setAction(0, ss.str());
         terminalPtr->set<Nice::Completion> ( _c, Nice::Date::now() );
         usleep(400000); // to be not faster than the GUI
     }
 }

/*
This map keeps all card commands that can be called via the terminal.
The module command will be send directly to the MoCon. The MoCon will complain if the command doesn't exist.
The terminal checks if the entered command is in this list and lock the card object if it is the case.
The integer value indicate that this command is a card command but it is not used.
The reason for the usage of the map is the possibility to search for the command IDs in the map - its easier than a vector implementation :).
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_VERSION, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_GET_REGISTRATION, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_SW_RESET, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_GET_ERROR_CODE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_RST_ERROR, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_XON_XOFF, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_GET_XON_XOFF, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_SET_SERIEL_RATE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_GET_SERIEL_RATE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_SET_CAN_RATE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_GET_CAN_RATE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_SET_MESSAGE_FLAG, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_GET_MESSAGE_FLAG, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_TELNET_LOGIN, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_TELNET_PWD, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_RESERVE_MOD, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_FREE_MOD, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_PLOT_RES_MOD, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_HUGE_DATA_RES, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_HUGE_DATA_FREE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_EXIT_TELNET, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_SET_IP_ADDRESS, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_GET_IP_ADDRESS, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_SET_GATE_ADDRESS, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_GET_GATE_ADDRESS, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_SET_MASK_ADDRESS, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MPIA_GET_MASK_ADDRESS, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_SET_FIRMWARE_SETTINGS, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_SET_MULTIUPDATE_SETTINGS, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_MOVE_MULTIUPDATE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_GET_FIRMWARE_SETTINGS, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_SET_DIGITAL_OUT_BIT, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_SET_DIGITAL_OUT_BYTE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_SET_DIGITAL_OUT_WORD, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_SET_DIGITAL_OUT_LONG, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_GET_DIGITAL_IN_BIT, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_GET_DIGITAL_IN_BYTE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_GET_DIGITAL_IN_WORD, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_GET_DIGITAL_IN_LONG, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_SET_TRACE_SAMPLE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_SET_TRACE_SAMPLE_NR, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_SET_TRACE_MODE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_TRACE_START, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_TRACE_STOP, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_CLEAR_TRACE_BUFFER, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_SET_EVENT_TRACE_SAMPLE, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_EVENT_TRACE_START, 0));
     m_cardCmd.insert( std::make_pair<unsigned int, unsigned int>(MOCON_EVENT_TRACE_STOP, 0));
*/

 void
 Basda::MoConNDevice::addCommandInterface()
 {
     m_config->setAtNode<Nice::Completion> ( "CMD.moveAbs",  Nice::Completion() );
     m_config->setAtNode<Nice::Completion> ( "CMD.moveRel",  Nice::Completion() );
     m_config->setAtNode<Nice::Completion> ( "CMD.moveHome",  Nice::Completion() );
     m_config->setAtNode<Nice::Completion> ( "CMD.traceTimeBased",  Nice::Completion() );
     m_config->setAtNode<Nice::Completion> ( "CMD.traceEventBased",  Nice::Completion() );
     m_config->setAtNode<Nice::Completion> ( "CMD.externalProfile",  Nice::Completion() );
     m_config->setAtNode<Nice::Completion> ( "CMD.testCommand",  Nice::Completion() );
     m_config->setAtNode<Nice::Completion> ( "CMD.timeOffset",  Nice::Completion() );

     m_moveAbsThread = new Basda::MoConNDeviceMoveAbsThread ( m_config->node("CMD.moveAbs").get(), this );
     m_moveRelThread = new Basda::MoConNDeviceMoveRelThread ( m_config->node("CMD.moveRel").get(), this );

     m_cmdThreads.add ( m_moveAbsThread );
     m_cmdThreads.add ( m_moveRelThread );
     m_cmdThreads.add ( new Basda::MoConNDeviceMoveHomeThread ( m_config->node("CMD.moveHome").get(), this ) );
     m_cmdThreads.add ( new Basda::MoConNDeviceTimeBasedTraceThread ( m_config->node("CMD.traceTimeBased").get(), this ) );
     m_cmdThreads.add ( new Basda::MoConNDeviceEventBasedTraceThread ( m_config->node("CMD.traceEventBased").get(), this ) );
     m_cmdThreads.add ( new Basda::MoConNDeviceExternalProfileThread ( m_config->node("CMD.externalProfile").get(), this ) );
     m_cmdThreads.add ( new Basda::MoConNDeviceTestCommandThread ( m_config->node("CMD.testCommand").get(), this ) );
     m_cmdThreads.add ( new Basda::MoConNDeviceTimeOffsetThread ( m_config->node("CMD.timeOffset").get(), this ) );

     m_config->setAtNode<Nice::Completion> ( "CMD.Stop",  Nice::Completion() );
     m_config->leaf("CMD.Stop")->applyAttribute<std::vector<std::string> >("LABEL", std::vector<std::string> >("Stop"));
     m_config->leaf("CMD.Stop")->applyAttribute<bool>("NOPROG", true);
     m_config->leaf("CMD.Stop")->applyAttribute<bool>("AUTOSYNC", true);
     m_config->leaf("CMD.Stop")->applyBridge
     (
         new Nice::PropertyBridgeMemFn<Nice::Completion, MoConNDevice> ( this, &MoConNDevice::stop ), "MoConNDevice_Stop"
     );

     m_config->setAtNode<Nice::Completion> ( "CMD.Abort",  Nice::Completion() );
     m_config->leaf("CMD.Abort")->applyAttribute<std::vector<std::string> >("LABEL", std::vector<std::string> >("ABORT"));
     m_config->leaf("CMD.Abort")->applyAttribute<bool>("NOPROG", true);
     m_config->leaf("CMD.Abort")->applyAttribute<bool>("AUTOSYNC", true);
     m_config->leaf("CMD.Abort")->applyBridge
     (
         new Nice::PropertyBridgeMemFn<Nice::Completion, MoConNDevice> ( this, &MoConNDevice::abort ), "MoConNDevice_Abort"
     );

     m_config->setAtNode<Nice::Completion> ( "CMD.getPosition",  Nice::Completion() );
     m_config->leaf("CMD.getPosition")->applyAttribute<std::vector<std::string> >("LABEL", std::vector<std::string> >("Get Position"));
     m_config->leaf("CMD.getPosition")->applyAttribute<bool>("NOPROG", true);
     m_config->leaf("CMD.getPosition")->applyAttribute<bool>("AUTOSYNC", true);
     m_config->leaf("CMD.getPosition")->applyBridge
     (
         new Nice::PropertyBridgeMemFn<Nice::Completion, MoConNDevice> ( this, &MoConNDevice::getPosition ), "MoConNDevice_getPosition"
     );

     m_config->setAtNode<Nice::Completion>( "CMD.terminal", Nice::Completion()  );
     m_config->leaf("CMD.terminal")->applyAttribute<bool>("ADVANCED", false );
     m_config->leaf("CMD.terminal")->applyBridge
     (
         new Nice::PropertyBridgeMemFn<Nice::Completion, MoConNDevice> ( this, &MoConNDevice::terminal ), "MoConNDevice_terminal"
     );

     m_config->leaf("VAR.UNIT"    )->applyBridge
     (
         new Nice::PropertyBridgeMemFn<Nice::Any, MoConNDevice> ( this, &MoConNDevice::unitChanged ), "MoConNDevice_unitChanged"
     );

     m_config->setAtNode<std::string> ( "",  "Drag and drop that node to get the control panel of this device." );
     m_config->leaf ()->applyAttribute<std::string>("CLASS", "BasdaMoConDeviceControl" );
     m_cmdThreads.start ();

     m_config->setAtNode<Nice::Completion>( "CMD.getReferenceTime", Nice::Completion()  );
     m_config->leaf("CMD.getReferenceTime")->applyAttribute<std::vector<std::string> >("LABEL", std::vector<std::string> >("Get Reference Time"));
     m_config->leaf("CMD.getReferenceTime")->applyAttribute<bool>("NOPROG", true);
     m_config->leaf("CMD.getReferenceTime")->applyAttribute<bool>("AUTOSYNC", true);
     m_config->leaf("CMD.getReferenceTime")->applyBridge
     (
         new Nice::PropertyBridgeMemFn<Nice::Completion, MoConNDevice> ( this, &MoConNDevice::getReferenceTime ), "MoConNDevice_getReferenceTime"
     );
     m_config->setAtNode<Nice::Completion>( "CMD.getCurrentTime", Nice::Completion()  );
     m_config->leaf("CMD.getCurrentTime")->applyAttribute<std::vector<std::string> >("LABEL", std::vector<std::string> >("Get Current Time"));
     m_config->leaf("CMD.getCurrentTime")->applyAttribute<bool>("NOPROG", true);
     m_config->leaf("CMD.getCurrentTime")->applyAttribute<bool>("AUTOSYNC", true);
     m_config->leaf("CMD.getCurrentTime")->applyBridge
     (
         new Nice::PropertyBridgeMemFn<Nice::Completion, MoConNDevice> ( this, &MoConNDevice::getCurrentTime ), "MoConNDevice_getCurrentTime"
     );
 }


#endif /* 0 */
