diff --git a/Modules/OpenIGTLink/files.cmake b/Modules/OpenIGTLink/files.cmake index 0e87986c24..e51038f5b4 100644 --- a/Modules/OpenIGTLink/files.cmake +++ b/Modules/OpenIGTLink/files.cmake @@ -1,14 +1,13 @@ set(CPP_FILES mitkIGTLClient.cpp mitkIGTLServer.cpp mitkIGTLDevice.cpp mitkIGTLMessageSource.cpp mitkIGTLDeviceSource.cpp mitkIGTLMessage.cpp - mitkIGTLMessageCommon.cpp mitkIGTLMessageFactory.cpp mitkIGTLMessageCloneHandler.h mitkIGTLDummyMessage.cpp mitkIGTLMessageQueue.cpp mitkIGTLMessageProvider.cpp ) diff --git a/Modules/OpenIGTLink/mitkIGTLClient.cpp b/Modules/OpenIGTLink/mitkIGTLClient.cpp index 9b09aafe73..dbbffa4452 100644 --- a/Modules/OpenIGTLink/mitkIGTLClient.cpp +++ b/Modules/OpenIGTLink/mitkIGTLClient.cpp @@ -1,123 +1,118 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkIGTLClient.h" //#include "mitkIGTTimeStamp.h" //#include "mitkIGTHardwareException.h" #include #include #include #include #include typedef itk::MutexLockHolder MutexLockHolder; mitk::IGTLClient::IGTLClient() : IGTLDevice() { } mitk::IGTLClient::~IGTLClient() { } bool mitk::IGTLClient::OpenConnection() { if (this->GetState() != Setup) { mitkThrowException(mitk::Exception) << "Can only try to open the connection if in setup mode"; return false; } std::string hostname = this->GetHostname(); int portNumber = this->GetPortNumber(); if (portNumber == -1 || hostname.size() <= 0) { //port number or hostname was not correct return false; } //create a new client socket m_Socket = igtl::ClientSocket::New(); //try to connect to the igtl server int response = dynamic_cast(m_Socket.GetPointer())-> ConnectToServer(hostname.c_str(), portNumber); //check the response if ( response != 0 ) { mitkThrowException(mitk::Exception) << "The client could not connect to " << hostname << " port: " << portNumber; return false; } // everything is initialized and connected so the communication can be started this->SetState(Ready); return true; } -void mitk::IGTLClient::Connect() -{ - -} - void mitk::IGTLClient::Receive() { //try to receive a message, if the socket is not present anymore stop the //communication unsigned int status = this->ReceivePrivate(this->m_Socket); if ( status == IGTL_STATUS_NOT_PRESENT ) { this->StopCommunicationWithSocket(this->m_Socket); MITK_WARN("IGTLClient") << "Lost connection to server socket."; } } void mitk::IGTLClient::Send() { igtl::MessageBase::Pointer curMessage; //get the latest message from the queue curMessage = this->m_SendQueue->PullMessage(); // there is no message => return if ( curMessage.IsNull() ) return; if ( this->SendMessagePrivate(curMessage.GetPointer(), this->m_Socket) ) { MITK_INFO("IGTLDevice") << "Successfully sent the message."; } else { MITK_WARN("IGTLDevice") << "Could not send the message."; } } void mitk::IGTLClient::StopCommunicationWithSocket(igtl::Socket* /*socket*/) { m_StopCommunicationMutex->Lock(); m_StopCommunication = true; m_StopCommunicationMutex->Unlock(); } diff --git a/Modules/OpenIGTLink/mitkIGTLClient.h b/Modules/OpenIGTLink/mitkIGTLClient.h index dcd7074c4f..f753d3c95e 100644 --- a/Modules/OpenIGTLink/mitkIGTLClient.h +++ b/Modules/OpenIGTLink/mitkIGTLClient.h @@ -1,94 +1,86 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIGTLCLIENT_H #define MITKIGTLCLIENT_H #include "mitkIGTLDevice.h" #include namespace mitk { - /** Documentation - * \brief superclass for open IGT link client + /** + * \brief Superclass for OpenIGTLink clients * - * implements the IGTLDevice interface for IGTL clients + * Implements the IGTLDevice interface for IGTLClients. In certain points it + * behaves different than the IGTLServer. The client connects directly to a + * server (it cannot connect to two different servers). Therefore, it has to + * check only this one connection. * - * \ingroup IGT + * \ingroup OpenIGTLink */ class MITK_OPENIGTLINK_EXPORT IGTLClient : public IGTLDevice { public: mitkClassMacro(IGTLClient, IGTLDevice) itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** - * \brief initialize the connection to the IGTL device + * \brief Establishes the connection between this client and the IGTL server. * - * \todo check this description - * - * OpenConnection() establishes the connection to the IGTL server by: - * - connection to the IGTL device - * - initializing the device - * @throw mitk::IGTHardwareException Throws an exception if there are errors while connecting to the device. - * @throw mitk::IGTException Throws a normal IGT exception if an error occures which is not related to the hardware. + * @throw mitk::Exception Throws an exception if the client is not in Setup + * mode or if it cannot connect to the defined host. */ virtual bool OpenConnection(); protected: - IGTLClient(); ///< Constructor - virtual ~IGTLClient(); ///< Destructor + /** Constructor */ + IGTLClient(); + /** Destructor */ + virtual ~IGTLClient(); /** * \brief Call this method to receive a message. * - * The message will be saved in the receive queue. + * The message will be saved in the receive queue. If the connection is lost + * it will stop the communication. */ virtual void Receive(); /** - * \brief Call this method to send a message. The message will be read from - * the queue + * \brief Call this method to send a message. + * + * The message will be read from the queue. */ virtual void Send(); /** - * \brief Call this method to check for other devices that want to connect - * to this one. + * \brief Stops the communication with the given socket. + * + * The client uses just one socket. Therefore, calling this function causes + * the stop of the communication. * - * In case of a client this method is doing nothing. In case of a server it - * is checking for other devices and if there is one it establishes a - * connection. */ - virtual void Connect(); - - /** - * \brief Stops the communication with the given socket. - * - * The client uses just one socket. Therefore, calling this function causes - * the stop of the communication. - * - */ virtual void StopCommunicationWithSocket(igtl::Socket*); }; } // namespace mitk #endif /* MITKIGTLCLIENT_H */ diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.cpp b/Modules/OpenIGTLink/mitkIGTLDevice.cpp index 71a0d4092c..5b43e6c420 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.cpp +++ b/Modules/OpenIGTLink/mitkIGTLDevice.cpp @@ -1,467 +1,479 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkIGTLDevice.h" //#include "mitkIGTTimeStamp.h" #include #include #include #include #include #include //remove later #include #include static const int SOCKET_SEND_RECEIVE_TIMEOUT_MSEC = 100; typedef itk::MutexLockHolder MutexLockHolder; mitk::IGTLDevice::IGTLDevice() : // m_Data(mitk::DeviceDataUnspecified), m_State(mitk::IGTLDevice::Setup), + m_Name("Unspecified Device"), m_StopCommunication(false), m_PortNumber(-1), - m_Name("Unspecified Device"), m_MultiThreader(NULL), m_ThreadID(0) { m_StopCommunicationMutex = itk::FastMutexLock::New(); m_StateMutex = itk::FastMutexLock::New(); // m_LatestMessageMutex = itk::FastMutexLock::New(); m_CommunicationFinishedMutex = itk::FastMutexLock::New(); // execution rights are owned by the application thread at the beginning m_CommunicationFinishedMutex->Lock(); m_MultiThreader = itk::MultiThreader::New(); // m_Data = mitk::DeviceDataUnspecified; // m_LatestMessage = igtl::MessageBase::New(); m_MessageFactory = mitk::IGTLMessageFactory::New(); m_SendQueue = mitk::IGTLMessageQueue::New(); m_ReceiveQueue = mitk::IGTLMessageQueue::New(); m_CommandQueue = mitk::IGTLMessageQueue::New(); } mitk::IGTLDevice::~IGTLDevice() { /* stop communication and disconnect from igtl device */ if (GetState() == Running) { this->StopCommunication(); } if (GetState() == Ready) { this->CloseConnection(); } /* cleanup tracking thread */ if ((m_ThreadID != 0) && (m_MultiThreader.IsNotNull())) { m_MultiThreader->TerminateThread(m_ThreadID); } m_MultiThreader = NULL; } mitk::IGTLDevice::IGTLDeviceState mitk::IGTLDevice::GetState() const { MutexLockHolder lock(*m_StateMutex); return m_State; } void mitk::IGTLDevice::SetState( IGTLDeviceState state ) { itkDebugMacro("setting m_State to " << state); MutexLockHolder lock(*m_StateMutex); // lock and unlock the mutex if (m_State == state) { return; } m_State = state; this->Modified(); } bool mitk::IGTLDevice::TestConnection() { return true; } unsigned int mitk::IGTLDevice::ReceivePrivate(igtl::Socket* socket) { // Create a message buffer to receive header igtl::MessageHeader::Pointer headerMsg; headerMsg = igtl::MessageHeader::New(); // Initialize receive buffer headerMsg->InitPack(); // Receive generic header from the socket int r = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), 1); if (r == 0) //connection error { // an error was received, therefor the communication with this socket // must be stopped return IGTL_STATUS_NOT_PRESENT; } else if (r == -1 ) //timeout { // a timeout was received, this is no error state, thus, do nothing return IGTL_STATUS_TIME_OUT; } else if (r == headerMsg->GetPackSize()) { // Deserialize the header and check the CRC int crcCheck = headerMsg->Unpack(1); if (crcCheck & igtl::MessageHeader::UNPACK_HEADER) { // Allocate a time stamp igtl::TimeStamp::Pointer ts; ts = igtl::TimeStamp::New(); // Get time stamp igtlUint32 sec; igtlUint32 nanosec; headerMsg->GetTimeStamp(ts); ts->GetTimeStamp(&sec, &nanosec); // std::cerr << "Time stamp: " // << sec << "." // << nanosec << std::endl; // std::cerr << "Dev type and name: " << headerMsg->GetDeviceType() << " " // << headerMsg->GetDeviceName() << std::endl; // headerMsg->Print(std::cout); //check the type of the received message //if it is a GET_, STP_ or RTS_ command push it into the command queue //otherwise continue reading the whole message from the socket const char* curDevType = headerMsg->GetDeviceType(); if ( std::strstr( curDevType, "GET_" ) != NULL || std::strstr( curDevType, "STP_" ) != NULL || std::strstr( curDevType, "RTS_" ) != NULL) { this->m_CommandQueue->PushMessage(headerMsg); this->InvokeEvent(CommandReceivedEvent()); return IGTL_STATUS_OK; } //Create a message according to the header message igtl::MessageBase::Pointer curMessage; curMessage = m_MessageFactory->CreateInstance(headerMsg); //check if the curMessage is created properly, if not the message type is //not supported and the message has to be skipped if ( curMessage.IsNull() ) { socket->Skip(headerMsg->GetBodySizeToRead(), 0); MITK_ERROR("IGTLDevice") << "The received type is not supported. Please " "add it to the message factory."; return IGTL_STATUS_NOT_FOUND; } //insert the header to the message and allocate the pack curMessage->SetMessageHeader(headerMsg); curMessage->AllocatePack(); // Receive transform data from the socket int receiveCheck = 0; receiveCheck = socket->Receive(curMessage->GetPackBodyPointer(), curMessage->GetPackBodySize()); if ( receiveCheck > 0 ) { int c = curMessage->Unpack(1); if ( !(c & igtl::MessageHeader::UNPACK_BODY) ) { // mitkThrow() << "crc error"; return IGTL_STATUS_CHECKSUM_ERROR; } //check the type of the received message //if it is a command push it into the command queue //otherwise into the normal receive queue //STP_ commands are handled here because they implemented additional //member variables that are not stored in the header message if ( std::strstr( curDevType, "STT_" ) != NULL ) { this->m_CommandQueue->PushMessage(curMessage); this->InvokeEvent(CommandReceivedEvent()); } else { this->m_ReceiveQueue->PushMessage(curMessage); this->InvokeEvent(MessageReceivedEvent()); } return IGTL_STATUS_OK; } else { MITK_ERROR("IGTLDevice") << "Received a valid header but could not " << "read the whole message."; return IGTL_STATUS_UNKNOWN_ERROR; } } else { //CRC check failed return IGTL_STATUS_CHECKSUM_ERROR; } } else { //Message size information and actual data size don't match. //this state is not suppossed to be reached, return unknown error return IGTL_STATUS_UNKNOWN_ERROR; } } void mitk::IGTLDevice::SendMessage(const mitk::IGTLMessage* msg) { this->SendMessage(msg->GetMessage()); } void mitk::IGTLDevice::SendMessage(igtl::MessageBase::Pointer msg) { //add the message to the queue m_SendQueue->PushMessage(msg); } unsigned int mitk::IGTLDevice::SendMessagePrivate(igtl::MessageBase::Pointer msg, igtl::Socket::Pointer socket) { //check the input message if ( msg.IsNull() ) { MITK_ERROR("IGTLDevice") << "Could not send message because message is not " "valid. Please check."; return false; } // add the name of this device to the message msg->SetDeviceName(this->GetName().c_str()); // Pack (serialize) and send msg->Pack(); int sendSuccess = socket->Send(msg->GetPackPointer(), msg->GetPackSize()); if (sendSuccess) return IGTL_STATUS_OK; else return IGTL_STATUS_UNKNOWN_ERROR; } void mitk::IGTLDevice::RunCommunication() { if (this->GetState() != Running) return; // keep lock until end of scope MutexLockHolder communicationFinishedLockHolder(*m_CommunicationFinishedMutex); // Because m_StopCommunication is used by two threads, access has to be guarded // by a mutex. To minimize thread locking, a local copy is used here bool localStopCommunication; // update the local copy of m_StopCommunication this->m_StopCommunicationMutex->Lock(); localStopCommunication = this->m_StopCommunication; this->m_StopCommunicationMutex->Unlock(); while ((this->GetState() == Running) && (localStopCommunication == false)) { // Check if other igtl devices want to connect with this one. This method // is overwritten for igtl servers but is doing nothing in case of a igtl // client this->Connect(); // Check if there is something to receive and store it in the message queue this->Receive(); // Check if there is something to send this->Send(); /* Update the local copy of m_StopCommunication */ this->m_StopCommunicationMutex->Lock(); localStopCommunication = m_StopCommunication; this->m_StopCommunicationMutex->Unlock(); // time to relax itksys::SystemTools::Delay(1); } // StopCommunication was called, thus the mode should be changed back to Ready now // that the tracking loop has ended. this->SetState(Ready); MITK_DEBUG("IGTLDevice::RunCommunication") << "Reached end of communication."; // returning from this function (and ThreadStartCommunication()) // this will end the thread return; } bool mitk::IGTLDevice::StartCommunication() { if (this->GetState() != Ready) return false; // go to mode Running this->SetState(Running); // set a timeout for the sending and receiving this->m_Socket->SetTimeout(SOCKET_SEND_RECEIVE_TIMEOUT_MSEC); // update the local copy of m_StopCommunication this->m_StopCommunicationMutex->Lock(); this->m_StopCommunication = false; this->m_StopCommunicationMutex->Unlock(); // transfer the execution rights to tracking thread m_CommunicationFinishedMutex->Unlock(); // start a new thread that executes the communication m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartCommunication, this); // mitk::IGTTimeStamp::GetInstance()->Start(this); return true; } bool mitk::IGTLDevice::StopCommunication() { if (this->GetState() == Running) // Only if the object is in the correct state { // m_StopCommunication is used by two threads, so we have to ensure correct // thread handling m_StopCommunicationMutex->Lock(); m_StopCommunication = true; m_StopCommunicationMutex->Unlock(); // we have to wait here that the other thread recognizes the STOP-command // and executes it m_CommunicationFinishedMutex->Lock(); // mitk::IGTTimeStamp::GetInstance()->Stop(this); // notify realtime clock // StopCommunication was called, thus the mode should be changed back // to Ready now that the tracking loop has ended. this->SetState(Ready); } return true; } bool mitk::IGTLDevice::CloseConnection() { if (this->GetState() == Setup) { return true; } else if (this->GetState() == Running) { this->StopCommunication(); } m_Socket->CloseSocket(); /* return to setup mode */ this->SetState(Setup); // m_SerialCommunication = NULL; return true; } bool mitk::IGTLDevice::SendRTSMessage(const char* type) { //construct the device type for the return message, it starts with RTS_ and //continues with the requested type std::string returnType("RTS_"); returnType.append(type); //create a return message igtl::MessageBase::Pointer rtsMsg = this->m_MessageFactory->CreateInstance(returnType); //if retMsg is NULL there is no return message defined and thus it is not //necessary to send one back if ( rtsMsg.IsNotNull() ) { this->SendMessage(rtsMsg); return true; } else { return false; } } +void mitk::IGTLDevice::Connect() +{ + +} + igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextMessage() { //copy the next message into the given msg igtl::MessageBase::Pointer msg = this->m_ReceiveQueue->PullMessage(); return msg; } igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextCommand() { //copy the next command into the given msg igtl::MessageBase::Pointer msg = this->m_CommandQueue->PullMessage(); return msg; } +void mitk::IGTLDevice::EnableInfiniteBufferingMode( + mitk::IGTLMessageQueue::Pointer queue, + bool enable) +{ + queue->EnableInfiniteBuffering(enable); +} + //std::string mitk::IGTLDevice::GetNextMessageInformation() //{ // return this->m_ReceiveQueue->GetNextMsgInformationString(); //} //std::string mitk::IGTLDevice::GetNextMessageDeviceType() //{ // return this->m_ReceiveQueue->GetNextMsgDeviceType(); //} //std::string mitk::IGTLDevice::GetNextCommandInformation() //{ // return this->m_CommandQueue->GetNextMsgInformationString(); //} //std::string mitk::IGTLDevice::GetNextCommandDeviceType() //{ // return this->m_CommandQueue->GetNextMsgDeviceType(); //} ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartCommunication(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; if (igtlDevice != NULL) { igtlDevice->RunCommunication(); } igtlDevice->m_ThreadID = 0; // erase thread id because thread will end. return ITK_THREAD_RETURN_VALUE; } diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.h b/Modules/OpenIGTLink/mitkIGTLDevice.h index ab5803308d..58ae64c13c 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.h +++ b/Modules/OpenIGTLink/mitkIGTLDevice.h @@ -1,358 +1,361 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIGTLDEVICE_H #define MITKIGTLDEVICE_H #include "mitkCommon.h" //itk #include "itkObject.h" #include "itkFastMutexLock.h" #include "itkMultiThreader.h" //igtl #include "igtlSocket.h" #include "igtlMessageBase.h" #include "igtlTransformMessage.h" //mitkIGTL #include "MitkOpenIGTLinkExports.h" #include "mitkIGTLMessageFactory.h" #include "mitkIGTLMessageQueue.h" #include "mitkIGTLMessage.h" namespace mitk { - /**Documentation - * \brief Interface for all Open IGT Link Devices + /** + * \brief Interface for all OpenIGTLink Devices * - * Defines the methods that are common for all devices using Open IGT Link. + * Defines the methods that are common for all devices using OpenIGTLink. It + * can open/close a connection, start/stop a communication and send/receive + * messages. + * + * It uses message queues to store the incoming and outgoing mails. They are + * configurable, you can set buffering on and off. + * + * The device is in one of three different states: Setup, Ready or Running. + * Setup is the initial state. From this state on you can call + * OpenConnection() and arrive in the Ready state. From the Ready state you + * call StartCommunication() to arrive in the Running state. Now the device + * is continuosly checking for new connections, receiving messages and + * sending messages. This runs in a seperate thread. To stop the communication + * call StopCommunication() (to arrive in Ready state) or CloseConnection() + * (to arrive in the Setup state). + * + * \ingroup OpenIGTLink * */ class MITK_OPENIGTLINK_EXPORT IGTLDevice : public itk::Object { public: mitkClassMacro(IGTLDevice, itk::Object) /** - * Type for state variable. The IGTLDevice is always in one of these states + * \brief Type for state variable. + * The IGTLDevice is always in one of these states. + * */ enum IGTLDeviceState {Setup, Ready, Running}; /** * \brief Opens a connection to the device * * This may only be called if there is currently no connection to the * device. If OpenConnection() is successful, the object will change from - * Setup state to Ready state + * Setup state to Ready state. */ virtual bool OpenConnection() = 0; /** * \brief Closes the connection to the device * * This may only be called if there is currently a connection to the * device, but device is not running (e.g. object is in Ready state) */ virtual bool CloseConnection(); /** * \brief Stops the communication between the two devices * - * This may only be called if there the device is in Running state + * This may only be called if the device is in Running state. */ virtual bool StopCommunication(); + /** + * \brief Starts the communication between the two devices + * + * This may only be called if the device is in Ready state. + */ bool StartCommunication(); + /** + * \brief Continuously checks for new connections, receives messages and + * sends messages. + * + * This may only be called if the device is in Running state and only from + * a seperate thread. + */ void RunCommunication(); /** - * \brief Sends a message via the open IGT Link. + * \brief Adds the given message to the sending queue * * This may only be called after the connection to the device has been * established with a call to OpenConnection(). Note that the message * is not send directly. This method just adds it to the send queue. + * \param msg The message to be added to the sending queue */ void SendMessage(igtl::MessageBase::Pointer msg); /** - * \brief Sends a message via the open IGT Link. + * \brief Adds the given message to the sending queue * * Convenience function to work with mitk::IGTLMessage directly. + * \param msg The message to be added to the sending queue */ void SendMessage(const IGTLMessage* msg); /** - * \brief return current object state (Setup, Ready or Running) + * \brief Returns current object state (Setup, Ready or Running) */ IGTLDeviceState GetState() const; /** - * \brief Returns the oldest command message - * \param msg A smartpointer to the message base where the oldest command - * shall be copied into - * \retval true The latest message is stored in msg - * \retval false The latest message could not been copied, do not use this - * data + * \brief Returns the oldest message in the command queue + * \return The oldest message from the command queue. */ igtl::MessageBase::Pointer GetNextCommand(); /** - * \brief Returns the oldest received message - * \param msg A smartpointer to the message base where the latest message - * shall be copied into - * \retval true The latest message is stored in msg - * \retval false The latest message could not been copied, do not use this - * data + * \brief Returns the oldest message in the receive queue + * \return The oldest message from the receive queue */ igtl::MessageBase::Pointer GetNextMessage(); -// /** -// * \brief Returns information about the oldest message in the receive queue -// */ -// std::string GetNextMessageInformation(); - -// /** -// * \brief Returns device type about the oldest message in the receive queue -// */ -// std::string GetNextMessageDeviceType(); - -// /** -// * \brief Returns information about the oldest message in the command queue -// */ -// std::string GetNextCommandInformation(); - -// /** -// * \brief Returns device type about the oldest message in the command queue -// */ -// std::string GetNextCommandDeviceType(); - - /** - * \brief return device data - */ -// igtl::MessageBase::Pointer GetData() const; - - /** - * \brief set device data - */ -// void SetData(IGTLDeviceData data); - /** * \brief Sets the port number of the device */ itkSetMacro(PortNumber,int); /** * \brief Returns the port number of the device */ itkGetMacro(PortNumber,int); /** * \brief Sets the ip/hostname of the device */ itkSetMacro(Hostname,std::string); /** * \brief Returns the ip/hostname of the device */ itkGetMacro(Hostname,std::string); /** * \brief Returns the name of this device */ itkGetConstMacro(Name, std::string); /** * \brief Sets the name of this device */ itkSetMacro(Name, std::string); /** * \brief Returns a const reference to the receive queue */ itkGetConstMacro(ReceiveQueue, mitk::IGTLMessageQueue::Pointer); /** * \brief Returns a const reference to the command queue */ itkGetConstMacro(CommandQueue, mitk::IGTLMessageQueue::Pointer); /** * \brief Returns a const reference to the send queue */ itkGetConstMacro(SendQueue, mitk::IGTLMessageQueue::Pointer); - /** * \brief Returns the message factory */ itkGetMacro(MessageFactory, mitk::IGTLMessageFactory::Pointer); /** * \brief static start method for the tracking thread. + * \param data a void pointer to the IGTLDevice object. */ static ITK_THREAD_RETURN_TYPE ThreadStartCommunication(void* data); /** - * \brief TestConnection() tries to connect to a IGTL server on the current + * \brief TestConnection() tries to connect to a IGTL device on the current * ip and port * - * \todo check this description + * \todo Implement this method. Send a status message and check the answer. * * TestConnection() tries to connect to a IGTL server on the current * ip and port and returns which device it has found. - * \return It returns the type of the device that answers. Throws an exception + * \return It returns the type of the device that answers. Throws an + * exception * if no device is available on that ip/port. - * @throw mitk::IGTHardwareException Throws an exception if there are errors + * @throw mitk::Exception Throws an exception if there are errors * while connecting to the device. */ virtual bool TestConnection(); /** * \brief Send RTS message of given type */ bool SendRTSMessage(const char* type); + /** + * \brief Sets the buffering mode of the given queue + */ + void EnableInfiniteBufferingMode(mitk::IGTLMessageQueue::Pointer queue, + bool enable = true); + protected: /** - * \brief Sends a message via the open IGT Link. + * \brief Sends a message. * * This may only be called after the connection to the device has been - * established with a call to OpenConnection() + * established with a call to OpenConnection(). This method uses the given + * socket to send the given MessageReceivedEvent + * + * \param msg the message to be sent + * \param socket the socket used to communicate with the other device * * \retval IGTL_STATUS_OK the message was sent * \retval IGTL_STATUS_UNKONWN_ERROR the message was not sent because an * unknown error occurred */ unsigned int SendMessagePrivate(igtl::MessageBase::Pointer msg, igtl::Socket::Pointer socket); /** * \brief Call this method to receive a message. * * The message will be saved in the receive queue. */ virtual void Receive() = 0; /** - * \brief Call this method to receive a message from the given client. + * \brief Call this method to receive a message from the given device. * * The message will be saved in the receive queue. * + * \param device the socket that connects this device with the other one. + * * \retval IGTL_STATUS_OK a message or a command was received * \retval IGTL_STATUS_NOT_PRESENT the socket is not connected anymore * \retval IGTL_STATUS_TIME_OUT the socket timed out * \retval IGTL_STATUS_CHECKSUM_ERROR the checksum of the received msg was * incorrect * \retval IGTL_STATUS_UNKNOWN_ERROR an unknown error occurred */ - unsigned int ReceivePrivate(igtl::Socket* client); + unsigned int ReceivePrivate(igtl::Socket* device); /** * \brief Call this method to send a message. The message will be read from - * the queue + * the queue. */ virtual void Send() = 0; /** * \brief Call this method to check for other devices that want to connect * to this one. * * In case of a client this method is doing nothing. In case of a server it * is checking for other devices and if there is one it establishes a * connection. */ - virtual void Connect() = 0; + virtual void Connect(); /** * \brief Stops the communication with the given socket * */ virtual void StopCommunicationWithSocket(igtl::Socket* socket) = 0; /** - * \brief change object state + * \brief change object state */ void SetState(IGTLDeviceState state); - IGTLDevice(); virtual ~IGTLDevice(); -// IGTLDeviceData m_Data; ///< current device Data - IGTLDeviceState m_State; ///< current object state (Setup, Ready or Running) - bool m_StopCommunication; ///< signal stop to thread - /** mutex to control access to m_StopThread */ + /** current object state (Setup, Ready or Running) */ + IGTLDeviceState m_State; + /** the name of this device */ + std::string m_Name; + + /** signal used to stop the thread*/ + bool m_StopCommunication; + /** mutex to control access to m_StopCommunication */ itk::FastMutexLock::Pointer m_StopCommunicationMutex; - /** mutex to manage control flow of StopTracking() */ + /** mutex used to make sure that the thread is just started once */ itk::FastMutexLock::Pointer m_CommunicationFinishedMutex; /** mutex to control access to m_State */ itk::FastMutexLock::Pointer m_StateMutex; - /** mutex to control access to m_Socket */ -// itk::FastMutexLock::Pointer m_SocketMutex; - /** mutex to control access to m_ReceiveQueue */ -// itk::FastMutexLock::Pointer m_ReceiveQueueMutex; - /** mutex to control access to m_SendQueue */ -// itk::FastMutexLock::Pointer m_SendQueueMutex; /** the hostname or ip of the device */ std::string m_Hostname; /** the port number of the device */ int m_PortNumber; /** the socket used to communicate with other IGTL devices */ igtl::Socket::Pointer m_Socket; - /** the latest received message */ -// igtl::MessageBase::Pointer m_LatestMessage; + /** The message receive queue */ mitk::IGTLMessageQueue::Pointer m_ReceiveQueue; /** The message send queue */ mitk::IGTLMessageQueue::Pointer m_SendQueue; /** A queue that stores just command messages received by this device */ mitk::IGTLMessageQueue::Pointer m_CommandQueue; + /** A message factory that provides the New() method for all msg types */ mitk::IGTLMessageFactory::Pointer m_MessageFactory; - /** the name of this device */ - std::string m_Name; private: /** creates worker thread that continuously polls interface for new messages */ itk::MultiThreader::Pointer m_MultiThreader; - int m_ThreadID; ///< ID of polling thread + /** ID of polling thread */ + int m_ThreadID; }; - /**Documentation + /** * @brief connect to this Event to get noticed when a message was received * */ itkEventMacro( MessageReceivedEvent , itk::AnyEvent ); - /**Documentation + /** * @brief connect to this Event to get noticed when a command was received * */ itkEventMacro( CommandReceivedEvent , itk::AnyEvent ); - /**Documentation + /** * @brief connect to this Event to get noticed when another igtl device * connects with this device. * */ itkEventMacro( NewClientConnectionEvent , itk::AnyEvent ); } // namespace mitk #endif /* MITKIGTLDEVICE_H */ diff --git a/Modules/OpenIGTLink/mitkIGTLDeviceSource.h b/Modules/OpenIGTLink/mitkIGTLDeviceSource.h index 30a14b3e30..4a04ba3392 100644 --- a/Modules/OpenIGTLink/mitkIGTLDeviceSource.h +++ b/Modules/OpenIGTLink/mitkIGTLDeviceSource.h @@ -1,194 +1,194 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef IGTLDEVICESOURCE_H_HEADER_INCLUDED_ #define IGTLDEVICESOURCE_H_HEADER_INCLUDED_ #include "mitkIGTLDevice.h" #include "mitkIGTLMessageSource.h" namespace mitk { - /**Documentation + /** * \brief Connects a mitk::IGTLDevice to a - * MITK-OpenIGTLink Message-Filterpipeline + * MITK-OpenIGTLink-Message-Filter-Pipeline * * This class is the source of most OpenIGTLink pipelines. It encapsulates a * mitk::IGTLDevice and provides the information/messages of the connected * OpenIGTLink devices as igtl::MessageBase objects. Note, that there is just * one single output. * */ class MITK_OPENIGTLINK_EXPORT IGTLDeviceSource : public IGTLMessageSource { public: mitkClassMacro(IGTLDeviceSource, IGTLMessageSource); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** *\brief These Constants are used in conjunction with Microservices */ static const std::string US_PROPKEY_IGTLDEVICENAME; /** * \brief sets the OpenIGTLink device that will be used as a data source */ virtual void SetIGTLDevice(mitk::IGTLDevice* td); /** * \brief returns the OpenIGTLink device that is used by this filter */ itkGetObjectMacro(IGTLDevice, mitk::IGTLDevice); /** *\brief Registers this object as a Microservice, making it available to every * module and/or plugin. To unregister, call UnregisterMicroservice(). */ virtual void RegisterAsMicroservice(); /** * \brief Establishes a connection to the OpenIGTLink device. If there is * already a connection the method does nothing. * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink * device was set with SetIGTLDevice(). Will throw a std::runtime_error if * the OpenIGTLink device returns an error. */ void Connect(); /** * \brief Closes the connection to the OpenIGTLink device * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink * device was set with SetIGTLDevice(). Will throw a std::runtime_error if * the OpenIGTLink device returns an error. */ void Disconnect(); /** * \brief starts the communication of the device. * This needs to be called before Update() or GetOutput()->Update(). If the * device is already communicating the method does nothing. * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink * device was set with SetIGTLDevice(). Will throw a std::runtime_error if * the OpenIGTLink device returns an error. */ void StartCommunication(); /** * \brief stops the communication of the device. * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink * device was set with SetIGTLDevice(). Will throw a std::runtime_error if * the OpenIGTLink device returns an error. */ void StopCommunication(); /** * \brief returns true if a connection to the OpenIGTLink device is established * */ virtual bool IsConnected(); /** * \brief returns true if communication is in progress * */ virtual bool IsCommunicating(); /** * \brief Used for pipeline update */ virtual void UpdateOutputInformation(); protected: IGTLDeviceSource(); virtual ~IGTLDeviceSource(); /** * \brief filter execute method * * queries the OpenIGTLink device for new messages and updates its output * igtl::MessageBase objects with it. * \warning Will raise a std::out_of_range exception, if tools were added to * the OpenIGTLink device after it was set as input for this filter */ virtual void GenerateData(); /** * \brief Create the necessary outputs for the m_IGTLDevice * * This Method is called internally whenever outputs need to be reset. Old * Outputs are deleted when called. **/ void CreateOutputs(); /** * \brief This method is called when the IGTL device hold by this class * receives a new message **/ virtual void OnIncomingMessage(); /** * \brief This method is called when the IGTL device hold by this class * receives a new command **/ virtual void OnIncomingCommand(); using Superclass::SetInput; /** * \brief Set input with id idx of this filter * */ virtual void SetInput( unsigned int idx, const IGTLMessage* msg ); /** * \brief Get the input of this filter */ const IGTLMessage* GetInput(void) const; /** * \brief Get the input with id idx of this filter */ const IGTLMessage* GetInput(unsigned int idx) const; /** * \brief Get the input with name messageName of this filter */ const IGTLMessage* GetInput(std::string msgName) const; /** *\brief return the index of the input with name msgName, throw * std::invalid_argument exception if that name was not found * * \warning if a subclass has inputs that have different data type than * mitk::IGTLMessage, they have to overwrite this method */ DataObjectPointerArraySizeType GetInputIndex(std::string msgName); /** *\brief return the index of the output with name msgName, -1 if no output * with that name was found * * \warning if a subclass has outputs that have different data type than * mitk::IGTLMessage, they have to overwrite this method */ DataObjectPointerArraySizeType GetOutputIndex(std::string msgName); /** the OpenIGTLink device that is used as a source for this filter object*/ mitk::IGTLDevice::Pointer m_IGTLDevice; }; } // namespace mitk #endif /* MITKIGTLDeviceSource_H_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageFactory.h b/Modules/OpenIGTLink/mitkIGTLMessageFactory.h index 80cc0d2689..f1749d1c62 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageFactory.h +++ b/Modules/OpenIGTLink/mitkIGTLMessageFactory.h @@ -1,173 +1,152 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIGTLMESSAGEFACTORYH_HEADER_INCLUDED_ #define MITKIGTLMESSAGEFACTORYH_HEADER_INCLUDED_ #include "MitkOpenIGTLinkExports.h" #include "mitkCommon.h" #include "igtlMessageBase.h" #include "igtlMessageHeader.h" #include "mitkIGTLMessageCloneHandler.h" namespace mitk { - /**Documentation + /** * \brief Factory class of supported OpenIGTLink message types * - * This class is a factory class of supported OpenIGTLink message types to - * localize the message creation code. + * This class is a factory for the creation of OpenIGTLink messages. It stores + * pairs of type and pointer to the message new method. Available standard types + * are already added but you can also add your custom types at runtime. * */ class MITK_OPENIGTLINK_EXPORT IGTLMessageFactory : public itk::Object { public: mitkClassMacro(IGTLMessageFactory, itk::Object) itkFactorylessNewMacro(Self); itkCloneMacro(Self); - -// virtual void PrintSelf(ostream& os); - /** * \brief Function pointer for storing New() static methods of * igtl::MessageBase classes */ typedef igtl::MessageBase::Pointer (*PointerToMessageBaseNew)(); /** * \brief Add message type name and pointer to IGTL message new function and * the clone handler * \param messageTypeName The name of the message type * \param messageTypeNewPointer Function pointer to the message type new * function (e.g. (PointerToMessageBaseNew)&igtl::ImageMessage::New ) - * \param msgClonePointer Function pointer to the message clone function - * (e.g. TBD ) + * \param cloneHandler pointer to the message clone object */ void AddMessageType(std::string messageTypeName, IGTLMessageFactory::PointerToMessageBaseNew messageTypeNewPointer, mitk::IGTLMessageCloneHandler::Pointer cloneHandler); /** * \brief Add message type name and pointer to IGTL message new function * Usage: * AddMessageType("IMAGE", (PointerToMessageBaseNew)&igtl::ImageMessage::New); * \param messageTypeName The name of the message type * \param messageTypeNewPointer Function pointer to the message type new * function (e.g. (PointerToMessageBaseNew)&igtl::ImageMessage::New ) */ virtual void AddMessageNewMethod(std::string messageTypeName, IGTLMessageFactory::PointerToMessageBaseNew messageTypeNewPointer); /** * \brief Get pointer to message type new function, or NULL if the message * type not registered * Usage: * igtl::MessageBase::Pointer message = GetMessageTypeNewPointer("IMAGE")(); */ virtual IGTLMessageFactory::PointerToMessageBaseNew GetMessageTypeNewPointer( std::string messageTypeName); /** * \brief Creates a new message instance fitting to the given type. * * If this type is not registered it returns NULL * Usage: * igtl::MessageBase::Pointer message = CreateInstance("IMAGE"); */ igtl::MessageBase::Pointer CreateInstance(std::string messageTypeName); /** * \brief Creates a new message according to the given header * \param msg The message header that defines the type of the message * This method checks the data type and creates a new message according to the * type. */ igtl::MessageBase::Pointer CreateInstance(igtl::MessageHeader::Pointer msg); /** - * \brief Add a clone function for the specified message type + * \brief Adds a clone function for the specified message type * \param msgTypeName The name of the message type - * \param msgClonePointer Function pointer to the message clone function + * \param msgCloneHandler Function pointer to the message clone function * (e.g. TBD ) */ virtual void AddMessageCloneHandler(std::string msgTypeName, mitk::IGTLMessageCloneHandler::Pointer msgCloneHandler); /** - * \brief Get pointer to message type clone function, or NULL if the message type is - * not registered - * Usage: igtl::TransformMessage::Pointer original = igtl::TransformMessage::New(); - * igtl::MessageBase::Pointer message = GetMessageTypeClonePointer("IMAGE")(original); + * \brief Get pointer to message type clone function, or NULL if the message + * type is not registered + * Usage: + * igtl::TransformMessage::Pointer original = igtl::TransformMessage::New(); + * igtl::MessageBase::Pointer message = + * GetCloneHandler("IMAGE")->Clone(original); */ - virtual mitk::IGTLMessageCloneHandler::Pointer GetCloneHandler(std::string messageTypeName); + virtual mitk::IGTLMessageCloneHandler::Pointer + GetCloneHandler(std::string messageTypeName); /** * \brief Clones the given message according to the available clone methods * \param msg The message that has to be cloned * This method checks the data type and clones the message according to this * type. */ igtl::MessageBase::Pointer Clone(igtl::MessageBase::Pointer msg); - /*! Print all supported OpenIGTLink message types */ - // virtual void PrintAvailableMessageTypes(ostream& os, vtkIndent indent); - - /*! Create a new igtl::MessageBase instance from message type, delete previous igtl::MessageBase if's not NULL */ - // PlusStatus CreateInstance(const char* aIgtlMessageType, igtl::MessageBase::Pointer& aMessageBase); - - /*! - Generate and pack IGTL messages from tracked frame - \param packValidTransformsOnly Control whether or not to pack transform messages if they contain invalid transforms - \param igtlMessageTypes List of message types to generate for a client - \param igtMessages Output list for the generated IGTL messages - \param trackedFrame Input tracked frame data used for IGTL message generation - \param transformNames List of transform names to send - \param imageTransformName Image transform name used in the IGTL image message - \param transformRepository Transform repository used for computing the selected transforms - */ - // PlusStatus PackMessages(const std::vector& igtlMessageTypes, std::vector& igtMessages, TrackedFrame& trackedFrame, - // std::vector& transformNames, std::vector& imageStreams, bool packValidTransformsOnly, vtkTransformRepository* transformRepository=NULL); - - /*! - * Returns available get messages + /** + * \brief Returns available get messages */ std::list GetAvailableMessageRequestTypes(); protected: IGTLMessageFactory(); virtual ~IGTLMessageFactory(); /** - * Map igt message types and the Clone() methods + * \brief Map igt message types and the Clone() methods */ std::map m_CloneHandlers; /** - * Map igt message types and the New() static methods of igtl::MessageBase + * \brief Map igt message types and the New() static methods of igtl::MessageBase * classes */ std::map m_NewMethods; private: IGTLMessageFactory(const IGTLMessageFactory&); - // void operator=(const IGTLMessageFactory&); - }; } #endif diff --git a/Modules/OpenIGTLink/mitkIGTLMessageProvider.h b/Modules/OpenIGTLink/mitkIGTLMessageProvider.h index 1fb3c49bb6..834102d92e 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageProvider.h +++ b/Modules/OpenIGTLink/mitkIGTLMessageProvider.h @@ -1,147 +1,159 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef IGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ #define IGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ #include "mitkIGTLDevice.h" #include "mitkIGTLDeviceSource.h" //itk #include "itkCommand.h" namespace mitk { - /**Documentation + /** * \brief Provides information/objects from a MITK-Pipeline to other OpenIGTLink * devices * * This class is intended as the drain of the pipeline. Other OpenIGTLink - * devices connect with the device hold by this provider. The other device asks - * for a special data. The provider checks if there are other IGTLMessageSources - * available that provide this data type. If yes, they connect with this source - * and send the message to the requesting device. + * devices connect with the IGTLDevice hold by this provider. The other device + * asks for a certain data type. The provider checks if there are other + * IGTLMessageSources available that provide this data type. If yes the provider + * connects with this source and sends the message to the requesting device. * + * If a STT message was received the provider looks for fitting messageSources. + * Once found it connects with it, starts a timing thread (which updates the + * pipeline) and sends the result to the requesting device. * + * If a GET message was received the provider just calls an update of the + * found source and sends the result without connecting to the source. + * + * If a STP message was received it stops the thread and disconnects from the + * previous source. + * + * So far the provider can just connect with one source. + * + * \ingroup OpenIGTLink */ class MITK_OPENIGTLINK_EXPORT IGTLMessageProvider : public IGTLDeviceSource { public: mitkClassMacro(IGTLMessageProvider, IGTLDeviceSource); itkFactorylessNewMacro(Self) itkCloneMacro(Self) typedef itk::SimpleMemberCommand ProviderCommand; /** * \brief sends the msg to the requesting client * * Note: so far it broadcasts the message to all registered clients */ void Send(const IGTLMessage* msg); protected: IGTLMessageProvider(); virtual ~IGTLMessageProvider(); /** * \brief filter execute method * * queries the OpenIGTLink device for new messages and updates its output * igtl::MessageBase objects with it. * \warning Will raise a std::out_of_range exception, if tools were added to * the OpenIGTLink device after it was set as input for this filter */ virtual void GenerateData(); /** * \brief Create the necessary outputs for the m_IGTLDevice * * This Method is called internally whenever outputs need to be reset. Old * Outputs are deleted when called. **/ void CreateOutputs(); /** * \brief This method is called when the IGTL device hold by this class * receives a new message **/ virtual void OnIncomingMessage(); /** * \brief This method is called when the IGTL device hold by this class * receives a new command **/ virtual void OnIncomingCommand(); /** *\brief Connects the input of this filter to the outputs of the given * IGTLMessageSource * * This method does not support smartpointer. use FilterX.GetPointer() to * retrieve a dumbpointer. */ void ConnectTo( mitk::IGTLMessageSource* UpstreamFilter ); /** *\brief Disconnects this filter from the outputs of the given * IGTLMessageSource * * This method does not support smartpointer. use FilterX.GetPointer() to * retrieve a dumbpointer. */ void DisconnectFrom( mitk::IGTLMessageSource* UpstreamFilter ); /** * \brief Looks for microservices that provide messages with the requested * type. **/ mitk::IGTLMessageSource::Pointer GetFittingSource(const char* requestedType); private: /** * \brief a command that has to be executed in the main thread */ ProviderCommand::Pointer m_StreamingCommand; /** * \brief Timer thread for generating a continuous time signal for the stream * * Everyt time the time is passed a time signal is invoked. * * \param pInfoStruct pointer to the mitkIGTLMessageProvider object * \return */ static ITK_THREAD_RETURN_TYPE TimerThread(void* pInfoStruct); int m_ThreadId; /** \brief timer thread will terminate after the next wakeup if set to true */ bool m_StopStreamingThread; itk::SmartPointer m_MultiThreader; /** \brief the time used for streaming */ unsigned int m_StreamingTime; /** \brief mutex for guarding m_Time */ itk::SmartPointer m_StreamingTimeMutex; /** \brief mutex for guarding m_StopStreamingThread */ itk::SmartPointer m_StopStreamingThreadMutex; }; } // namespace mitk #endif /* MITKIGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp b/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp index 6740ac8221..26f3e91d81 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp +++ b/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp @@ -1,123 +1,142 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkIGTLMessageQueue.h" #include #include "igtlMessageBase.h" void mitk::IGTLMessageQueue::PushMessage( igtl::MessageBase::Pointer message ) { this->m_Mutex->Lock(); - this->m_Queue.push_back( message ); + if ( this->m_BufferingType == IGTLMessageQueue::Infinit ) + { + this->m_Queue.push_back( message ); + } + else //NoBuffering + { + this->m_Queue.clear(); + this->m_Queue.push_back( message ); + } this->m_Mutex->Unlock(); } igtl::MessageBase::Pointer mitk::IGTLMessageQueue::PullMessage() { this->m_Mutex->Lock(); igtl::MessageBase::Pointer ret = NULL; if ( this->m_Queue.size() > 0 ) { ret = this->m_Queue.front(); this->m_Queue.pop_front(); } this->m_Mutex->Unlock(); return ret; } std::string mitk::IGTLMessageQueue::GetNextMsgInformationString() { this->m_Mutex->Lock(); std::stringstream s; if ( this->m_Queue.size() > 0 ) { s << "Device Type: " << this->m_Queue.front()->GetDeviceType() << std::endl; s << "Device Name: " << this->m_Queue.front()->GetDeviceName() << std::endl; } else { s << "No Msg"; } this->m_Mutex->Unlock(); return s.str(); } std::string mitk::IGTLMessageQueue::GetNextMsgDeviceType() { this->m_Mutex->Lock(); std::stringstream s; if ( this->m_Queue.size() > 0 ) { s << this->m_Queue.front()->GetDeviceType(); } else { s << ""; } this->m_Mutex->Unlock(); return s.str(); } std::string mitk::IGTLMessageQueue::GetLatestMsgInformationString() { this->m_Mutex->Lock(); std::stringstream s; if ( this->m_Queue.size() > 0 ) { s << "Device Type: " << this->m_Queue.back()->GetDeviceType() << std::endl; s << "Device Name: " << this->m_Queue.back()->GetDeviceName() << std::endl; } else { s << "No Msg"; } this->m_Mutex->Unlock(); return s.str(); } std::string mitk::IGTLMessageQueue::GetLatestMsgDeviceType() { this->m_Mutex->Lock(); std::stringstream s; if ( this->m_Queue.size() > 0 ) { s << this->m_Queue.back()->GetDeviceType(); } else { s << ""; } this->m_Mutex->Unlock(); return s.str(); } int mitk::IGTLMessageQueue::GetSize() { return this->m_Queue.size(); } +void mitk::IGTLMessageQueue::EnableInfiniteBuffering(bool enable) +{ + this->m_Mutex->Lock(); + if ( enable ) + this->m_BufferingType = IGTLMessageQueue::Infinit; + else + this->m_BufferingType = IGTLMessageQueue::NoBuffering; + this->m_Mutex->Unlock(); +} + mitk::IGTLMessageQueue::IGTLMessageQueue() { this->m_Mutex = itk::FastMutexLock::New(); + this->m_BufferingType = IGTLMessageQueue::Infinit; } mitk::IGTLMessageQueue::~IGTLMessageQueue() { this->m_Mutex->Unlock(); } diff --git a/Modules/OpenIGTLink/mitkIGTLMessageQueue.h b/Modules/OpenIGTLink/mitkIGTLMessageQueue.h index b29f735f0c..9047e8c4d8 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageQueue.h +++ b/Modules/OpenIGTLink/mitkIGTLMessageQueue.h @@ -1,72 +1,118 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef IGTLMessageQueue_H #define IGTLMessageQueue_H #include "MitkOpenIGTLinkExports.h" #include "itkObject.h" #include "itkFastMutexLock.h" #include "mitkCommon.h" #include #include "igtlMessageBase.h" namespace mitk { /** * \class IGTLMessageQueue * \brief Thread safe message queue to store OpenIGTLink messages. + * + * \ingroup OpenIGTLink */ class MITK_OPENIGTLINK_EXPORT IGTLMessageQueue : public itk::Object { public: mitkClassMacro(mitk::IGTLMessageQueue, itk::Object) itkFactorylessNewMacro(Self) itkCloneMacro(Self) + /** + * \brief Different buffering types + * Infinit buffering means that you can push as many messages as you want + * NoBuffering means that the queue just stores a single message + */ + enum BufferingType {Infinit, NoBuffering}; + + /** + * \brief Adds the message to the queue + */ void PushMessage( igtl::MessageBase::Pointer message ); + /** + * \brief Returns and removes the oldest message from the queue + */ igtl::MessageBase::Pointer PullMessage(); + /** + * \brief Get the number of messages in the queue + */ int GetSize(); + /** + * \brief Returns a string with information about the oldest message in the + * queue + */ std::string GetNextMsgInformationString(); + + /** + * \brief Returns the device type of the oldest message in the queue + */ std::string GetNextMsgDeviceType(); + + /** + * \brief Returns a string with information about the oldest message in the + * queue + */ std::string GetLatestMsgInformationString(); + + /** + * \brief Returns the device type of the oldest message in the queue + */ std::string GetLatestMsgDeviceType(); + /** + * \brief Sets infinite buffering on/off. + * Initiale value is enabled. + */ + void EnableInfiniteBuffering(bool enable); + protected: IGTLMessageQueue(); virtual ~IGTLMessageQueue(); protected: /** * \brief Mutex to take car of the queue */ itk::FastMutexLock::Pointer m_Mutex; /** * \brief the queue that stores pointer to the inserted messages */ std::deque< igtl::MessageBase::Pointer > m_Queue; + + /** + * \brief defines the kind of buffering + */ + BufferingType m_BufferingType; }; } #endif diff --git a/Modules/OpenIGTLink/mitkIGTLMessageSource.h b/Modules/OpenIGTLink/mitkIGTLMessageSource.h index 8b481269ed..f366789d46 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageSource.h +++ b/Modules/OpenIGTLink/mitkIGTLMessageSource.h @@ -1,212 +1,212 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIGTLMESSAGESOURCE_H_HEADER_INCLUDED_ #define MITKIGTLMESSAGESOURCE_H_HEADER_INCLUDED_ #include #include "mitkPropertyList.h" #include "MitkOpenIGTLinkExports.h" #include "mitkIGTLMessage.h" // Microservices #include #include //itk #include namespace mitk { - /**Documentation + /** * \brief OpenIGTLink message source * * Base class for all OpenIGTLink filters that produce OpenIGTLink message * objects as output. This class defines the output-interface for * OpenIGTLinkMessageFilters. * \warning: if Update() is called on any output object, all IGTLMessage filters * will generate new output data for all outputs, not just the one on which * Update() was called. * */ class MITK_OPENIGTLINK_EXPORT IGTLMessageSource : public itk::ProcessObject { public: mitkClassMacro(IGTLMessageSource, itk::ProcessObject); /** @return Returns a human readable name of this source. There will be a * default name, or you can set the name with the method SetName() if you * want to change it. */ itkGetMacro(Name,std::string); /** @brief Sets the human readable name of this source. There is also a * default name, but you can use this method if you need to define it on your * own. */ itkSetMacro(Name,std::string); /** @return Returns a human readable type of this source. There will be a * default type, or you can set the name with the method SetType(). You have * to set this parameter otherwise it will not be found by the message * provider. */ itkGetMacro(Type,std::string); /** @return Returns a human readable type of this source. There will be a * default type, or you can set the name with the method SetType(). You have * to set this parameter otherwise it will not be found by the message * provider. */ itkSetMacro(Type,std::string); /** *\brief return the output (output with id 0) of the filter */ IGTLMessage* GetOutput(void); /** *\brief return the output with id idx of the filter */ IGTLMessage* GetOutput(DataObjectPointerArraySizeType idx); /** *\brief return the output with name messageName of the filter */ IGTLMessage* GetOutput(const std::string& messageName); /** *\brief return the index of the output with name messageName, -1 if no output * with that name was found * * \warning if a subclass has outputs that have different data type than * igtl::MessageBase, they have to overwrite this method */ DataObjectPointerArraySizeType GetOutputIndex(std::string messageName); /** *\brief Registers this object as a Microservice, making it available to every * module and/or plugin. To unregister, call UnregisterMicroservice(). */ virtual void RegisterAsMicroservice(); /** *\brief Registers this object as a Microservice, making it available to every * module and/or plugin. */ virtual void UnRegisterMicroservice(); /** *\brief Returns the id that this device is registered with. The id will only * be valid, if the IGTLMessageSource has been registered using * RegisterAsMicroservice(). */ std::string GetMicroserviceID(); /** *\brief These Constants are used in conjunction with Microservices */ static const std::string US_INTERFACE_NAME; static const std::string US_PROPKEY_DEVICENAME; static const std::string US_PROPKEY_DEVICETYPE; static const std::string US_PROPKEY_ID; static const std::string US_PROPKEY_ISACTIVE; //NOT IMPLEMENTED YET! /** *\brief Graft the specified DataObject onto this ProcessObject's output. * * See itk::ImageSource::GraftNthOutput for details */ virtual void GraftNthOutput(unsigned int idx, itk::DataObject *graft); /** * \brief Graft the specified DataObject onto this ProcessObject's output. * * See itk::ImageSource::Graft Output for details */ virtual void GraftOutput(itk::DataObject *graft); /** * Allocates a new output object and returns it. Currently the * index idx is not evaluated. * @param idx the index of the output for which an object should be created * @returns the new object */ virtual itk::DataObject::Pointer MakeOutput ( DataObjectPointerArraySizeType idx ); /** * This is a default implementation to make sure we have something. * Once all the subclasses of ProcessObject provide an appopriate * MakeOutput(), then ProcessObject::MakeOutput() can be made pure * virtual. */ virtual itk::DataObject::Pointer MakeOutput(const DataObjectIdentifierType &name); /** * \brief Set all filter parameters as the PropertyList p * * This method allows to set all parameters of a filter with one * method call. For the names of the parameters, take a look at * the GetParameters method of the filter * This method has to be overwritten by each MITK-IGT filter. */ virtual void SetParameters(const mitk::PropertyList*){}; /** * \brief Get all filter parameters as a PropertyList * * This method allows to get all parameters of a filter with one * method call. The returned PropertyList must be assigned to a * SmartPointer immediately, or else it will get destroyed. * Every filter must overwrite this method to create a filter-specific * PropertyList. Note that property names must be unique over all * MITK-IGT filters. Therefore each filter should use its name as a prefix * for each property name. * Secondly, each filter should list the property names and data types * in the method documentation. */ virtual mitk::PropertyList::ConstPointer GetParameters() const; /** *\brief Sets the fps used for streaming this source */ void SetFPS(unsigned int fps); /** *\brief Gets the fps used for streaming this source */ unsigned int GetFPS(); protected: IGTLMessageSource(); virtual ~IGTLMessageSource(); std::string m_Name; std::string m_Type; /** mutex to control access to m_StreamingFPS */ itk::FastMutexLock::Pointer m_StreamingFPSMutex; /** The frames per second used for streaming */ unsigned int m_StreamingFPS; us::ServiceRegistration m_ServiceRegistration; }; } // namespace mitk // This is the microservice declaration. Do not meddle! MITK_DECLARE_SERVICE_INTERFACE(mitk::IGTLMessageSource, "org.mitk.services.IGTLMessageSource") #endif /* MITKIGTLMESSAGESOURCE_H_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLServer.h b/Modules/OpenIGTLink/mitkIGTLServer.h index 9b0617448b..ebd37948d0 100644 --- a/Modules/OpenIGTLink/mitkIGTLServer.h +++ b/Modules/OpenIGTLink/mitkIGTLServer.h @@ -1,109 +1,113 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIGTLSERVER_H #define MITKIGTLSERVER_H #include "mitkIGTLDevice.h" #include namespace mitk { - /** Documentation - * \brief superclass for open IGT link server + /** + * \brief Superclass for OpenIGTLink server * - * implements the IGTLDevice interface for IGTL servers + * Implements the IGTLDevice interface for IGTLServers. In certain points it + * behaves different than the IGTLClient. The client connects directly to a + * server (it cannot connect to two different servers) while the server can + * connect to several clients. Therefore, it is necessary for the server to + * have a list with registered sockets. * - * \ingroup IGT + * \ingroup OpenIGTLink */ class MITK_OPENIGTLINK_EXPORT IGTLServer : public IGTLDevice { public: mitkClassMacro(IGTLServer, IGTLDevice) itkFactorylessNewMacro(Self) itkCloneMacro(Self) typedef std::list SocketListType; typedef SocketListType::iterator SocketListIteratorType; /** - * \brief initialize the connection for the IGTL device + * \brief Initialize the connection for the IGTLServer * - * \todo check this description * - * OpenConnection() starts the IGTL server so that clients can connect to it - * @throw mitk::IGTHardwareException Throws an exception if there are errors - * while connecting to the device. - * @throw mitk::IGTException Throws a normal IGT exception if an error occures - * which is not related to the hardware. + * OpenConnection() starts the IGTLServer socket so that clients can connect + * to it. + * @throw mitk::Exception Throws an exception if the given port is occupied. */ virtual bool OpenConnection(); protected: - IGTLServer(); ///< Constructor - virtual ~IGTLServer(); ///< Destructor + /** Constructor */ + IGTLServer(); + /** Destructor */ + virtual ~IGTLServer(); /** * \brief Call this method to check for other devices that want to connect * to this one. * * In case of a client this method is doing nothing. In case of a server it * is checking for other devices and if there is one it establishes a - * connection. + * connection and adds the socket to m_RegisteredClients. */ virtual void Connect(); /** * \brief Call this method to receive a message. * * The message will be saved in the receive queue. */ virtual void Receive(); /** - * \brief Call this method to send a message. The message will be read from - * the queue + * \brief Call this method to send a message. + * The message will be read from the queue. So far the message is send to all + * connected sockets (broadcast). */ virtual void Send(); /** * \brief Stops the communication with the given sockets. * * This method removes the given sockets from the registered clients list * */ virtual void StopCommunicationWithSocket(SocketListType& toBeRemovedSockets); /** * \brief Stops the communication with the given socket. * * This method removes the given socket from the registered clients list * */ virtual void StopCommunicationWithSocket(igtl::Socket* client); /** - * @brief A list with all registered clients + * \brief A list with all registered clients */ SocketListType m_RegisteredClients; }; } // namespace mitk #endif /* MITKIGTLSERVER_H */ diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp index 3a82b985fa..f67d9fb589 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp @@ -1,413 +1,429 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkIGTLDeviceSourceManagementWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include const std::string QmitkIGTLDeviceSourceManagementWidget::VIEW_ID = "org.mitk.views.igtldevicesourcemanagementwidget"; QmitkIGTLDeviceSourceManagementWidget::QmitkIGTLDeviceSourceManagementWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false) { m_Controls = NULL; + this->m_IGTLDevice = NULL; CreateQtPartControl(this); } QmitkIGTLDeviceSourceManagementWidget::~QmitkIGTLDeviceSourceManagementWidget() { } void QmitkIGTLDeviceSourceManagementWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLDeviceSourceManagementWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } // set the validator for the ip edit box (values must be between 0 and 255 and // there are four of them, seperated with a point QRegExpValidator *v = new QRegExpValidator(this); QRegExp rx("((1{0,1}[0-9]{0,2}|2[0-4]{1,1}[0-9]{1,1}|25[0-5]{1,1})\\.){3,3}(1{0,1}[0-9]{0,2}|2[0-4]{1,1}[0-9]{1,1}|25[0-5]{1,1})"); v->setRegExp(rx); m_Controls->editIP->setValidator(v); // set the validator for the port edit box (values must be between 1 and 65535) m_Controls->editPort->setValidator(new QIntValidator(1, 65535, this)); //connect slots with signals CreateConnections(); } void QmitkIGTLDeviceSourceManagementWidget::CreateConnections() { if (m_Controls) { // connect the widget items with the methods connect( m_Controls->butConnect, SIGNAL(clicked()), this, SLOT(OnConnect())); connect( m_Controls->editPort, SIGNAL(editingFinished()), this, SLOT(OnPortChanged()) ); connect( m_Controls->editIP, SIGNAL(editingFinished()), this, SLOT(OnHostnameChanged()) ); connect( m_Controls->butSend, SIGNAL(clicked()), this, SLOT(OnSendMessage())); connect( m_Controls->butSendCommand, SIGNAL(clicked()), this, SLOT(OnSendCommand())); connect( m_Controls->commandsComboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(OnCommandChanged(const QString &))); + connect( m_Controls->bufferMsgCheckBox, SIGNAL(stateChanged(int)), + this, SLOT(OnBufferIncomingMessages(int))); } } void QmitkIGTLDeviceSourceManagementWidget::LoadSource( mitk::IGTLDeviceSource::Pointer sourceToLoad) { //reset the GUI DisableSourceControls(); //reset the observers if ( this->m_IGTLDevice != NULL ) { this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); } if(sourceToLoad.IsNotNull()) { this->m_IGTLDeviceSource = sourceToLoad; //get the device this->m_IGTLDevice = this->m_IGTLDeviceSource->GetIGTLDevice(); //check the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDevice->GetState(); //check if the device is a server or a client if ( dynamic_cast( this->m_IGTLDeviceSource->GetIGTLDevice()) == NULL ) { m_IsClient = false; } else { m_IsClient = true; } switch (state) { case mitk::IGTLDevice::Setup: if ( !m_IsClient ) { m_Controls->butConnect->setText("Go Online"); } else { m_Controls->butConnect->setText("Connect"); } break; case mitk::IGTLDevice::Ready: case mitk::IGTLDevice::Running: this->m_Controls->butConnect->setText("Disconnect"); this->m_Controls->editIP->setEnabled(false); this->m_Controls->editPort->setEnabled(false); this->m_Controls->editSend->setEnabled(true); this->m_Controls->butSend->setEnabled(true); this->m_Controls->commandsComboBox->setEnabled(true); this->m_Controls->butSendCommand->setEnabled(true); this->m_Controls->logSendReceiveMsg->setEnabled(true); + this->m_Controls->bufferMsgCheckBox->setEnabled(true); break; default: mitkThrow() << "Invalid Device State"; break; } m_Controls->selectedSourceLabel->setText(m_IGTLDeviceSource->GetName().c_str()); //add observer for new message receiving // typedef itk::MemberCommand< QmitkIGTLDeviceSourceManagementWidget > CurCommandType; // CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); // messageReceivedCommand->SetCallbackFunction( // this, &QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived ); // this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); typedef itk::MemberCommand< QmitkIGTLDeviceSourceManagementWidget > CurCommandType; m_MessageReceivedCommand = CurCommandType::New(); m_MessageReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived ); this->m_MessageReceivedObserverTag = this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), m_MessageReceivedCommand); typedef itk::MemberCommand< QmitkIGTLDeviceSourceManagementWidget > CurCommandType; CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); commandReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnCommandReceived ); this->m_CommandReceivedObserverTag = this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); //Fill the commands combo box with all available commands FillCommandsComboBox(); //enable the controls of this widget EnableSourceControls(); } else { m_IGTLDeviceSource = NULL; } } void QmitkIGTLDeviceSourceManagementWidget::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkIGTLDeviceSourceManagementWidget::DisableSourceControls() { m_Controls->selectedSourceLabel->setText(""); m_Controls->editIP->setEnabled(false); m_Controls->editPort->setEnabled(false); m_Controls->editSend->setEnabled(false); m_Controls->butSendCommand->setEnabled(false); m_Controls->fpsSpinBox->setEnabled(false); m_Controls->commandsComboBox->setEnabled(false); m_Controls->butSend->setEnabled(false); + m_Controls->bufferMsgCheckBox->setEnabled(false); // m_Controls->m_AddTool->setEnabled(false); // m_Controls->m_LoadTool->setEnabled(false); // m_Controls->m_selectedLabel->setEnabled(false); // m_Controls->m_DeleteTool->setEnabled(false); // m_Controls->m_EditTool->setEnabled(false); // m_Controls->m_SaveTool->setEnabled(false); // m_Controls->m_ToolList->setEnabled(false); // m_Controls->m_SaveStorage->setEnabled(false); // m_Controls->m_ToolLabel->setEnabled(false); } void QmitkIGTLDeviceSourceManagementWidget::EnableSourceControls() { if ( this->m_IsClient ) { m_Controls->editIP->setEnabled(true); } m_Controls->editPort->setEnabled(true); m_Controls->butConnect->setEnabled(true); // m_Controls->fpsSpinBox->setEnabled(true); // m_Controls->editSend->setEnabled(false); // m_Controls->m_AddTool->setEnabled(true); // m_Controls->m_LoadTool->setEnabled(true); // m_Controls->m_selectedLabel->setEnabled(true); // m_Controls->m_DeleteTool->setEnabled(true); // m_Controls->m_EditTool->setEnabled(true); // m_Controls->m_SaveTool->setEnabled(true); // m_Controls->m_ToolList->setEnabled(true); // m_Controls->m_SaveStorage->setEnabled(true); // m_Controls->m_ToolLabel->setEnabled(true); } void QmitkIGTLDeviceSourceManagementWidget::OnConnect() { if(m_Controls->butConnect->text() == "Connect" || m_Controls->butConnect->text() == "Go Online" ) { QString port = m_Controls->editPort->text(); m_IGTLDevice->SetPortNumber(port.toInt()); std::string hostname = m_Controls->editIP->text().toStdString(); m_IGTLDevice->SetHostname(hostname); if ( m_IGTLDevice->OpenConnection() ) { if ( m_IGTLDevice->StartCommunication() ) { this->m_Controls->editIP->setEnabled(false); this->m_Controls->editPort->setEnabled(false); this->m_Controls->editSend->setEnabled(true); this->m_Controls->butSend->setEnabled(true); this->m_Controls->commandsComboBox->setEnabled(true); this->m_Controls->butSendCommand->setEnabled(true); this->m_Controls->logSendReceiveMsg->setEnabled(true); + this->m_Controls->bufferMsgCheckBox->setEnabled(true); this->m_Controls->butConnect->setText("Disconnect"); if ( this->m_IsClient ) { MITK_INFO("IGTLDeviceSourceManagementWidget") << "Successfully connected to " << hostname << " on port " << port.toStdString(); } } else { MITK_ERROR("QmitkIGTLDeviceSourceManagementWidget") << "Could not start a communication with the" "server because the client is in the wrong state"; } } else { MITK_ERROR("QmitkIGTLDeviceSourceManagementWidget") << "Could not connect to the server. " "Please check the hostname and port."; } } else { if ( this->m_IsClient ) m_Controls->editIP->setEnabled(true); m_Controls->editPort->setEnabled(true); m_Controls->editSend->setEnabled(false); m_Controls->butSend->setEnabled(false); m_Controls->butSendCommand->setEnabled(false); m_Controls->commandsComboBox->setEnabled(false); + m_Controls->bufferMsgCheckBox->setEnabled(false); m_Controls->butConnect->setText("Connect"); m_IGTLDevice->CloseConnection(); MITK_INFO("QmitkIGTLDeviceSourceManagementWidget") << "Closed connection"; } } void QmitkIGTLDeviceSourceManagementWidget::OnPortChanged() { } void QmitkIGTLDeviceSourceManagementWidget::OnHostnameChanged() { } void QmitkIGTLDeviceSourceManagementWidget::OnSendCommand() { //Set the frames per second of the current command in case of a STT_ command if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_BIND" ) == 0 ) { ((igtl::StartBindMessage*)this->m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } else if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_QTDATA" ) == 0 ) { ((igtl::StartQuaternionTrackingDataMessage*)m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } else if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_TDATA" ) == 0 ) { ((igtl::StartTrackingDataMessage*)this->m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } m_IGTLDevice->SendMessage(m_CurrentCommand.GetPointer()); if ( this->m_Controls->logSendReceiveMsg->isChecked() ) { MITK_INFO("IGTLDeviceSourceManagementWidget") << "Sent command with DeviceType: " << m_CurrentCommand->GetDeviceType(); } } void QmitkIGTLDeviceSourceManagementWidget::OnCommandChanged( const QString & curCommand) { if ( curCommand.isEmpty() ) return; mitk::IGTLMessageFactory::Pointer msgFactory = this->m_IGTLDevice->GetMessageFactory(); //create a new message that fits to the selected get message type command this->m_CurrentCommand = msgFactory->CreateInstance( curCommand.toStdString()); //enable/disable the FPS spinbox this->m_Controls->fpsSpinBox->setEnabled(curCommand.contains("STT_")); } void QmitkIGTLDeviceSourceManagementWidget::OnSendMessage() { std::string toBeSend = m_Controls->editSend->text().toStdString(); igtl::StringMessage::Pointer msg = igtl::StringMessage::New(); msg->SetString(toBeSend); m_IGTLDevice->SendMessage(msg.GetPointer()); if ( this->m_Controls->logSendReceiveMsg->isChecked() ) { MITK_INFO("IGTLDeviceSourceManagementWidget") << "Sent message with DeviceType: " << msg->GetDeviceType(); } } void QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived( itk::Object* caller, const itk::EventObject&/*event*/) { //get the IGTL device that invoked this event mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; if ( this->m_Controls->logSendReceiveMsg->isChecked() ) { MITK_INFO("IGTLDeviceSourceManagementWidget") << "Received a message: " << dev->GetReceiveQueue()->GetLatestMsgInformationString(); } } void QmitkIGTLDeviceSourceManagementWidget::OnCommandReceived( itk::Object* caller, const itk::EventObject&/*event*/) { //get the IGTL device that invoked this event mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; if ( this->m_Controls->logSendReceiveMsg->isChecked() ) { MITK_INFO("IGTLDeviceSourceManagementWidget") << "Received a command: " << dev->GetCommandQueue()->GetLatestMsgInformationString(); } } +void QmitkIGTLDeviceSourceManagementWidget::OnBufferIncomingMessages(int state) +{ + if ( this->m_IGTLDevice ) + { + this->m_IGTLDevice->EnableInfiniteBufferingMode( + this->m_IGTLDevice->GetReceiveQueue(), (bool)state); + } +} + void QmitkIGTLDeviceSourceManagementWidget::FillCommandsComboBox() { //load the msg factory from the client (maybe this will be moved later on) mitk::IGTLMessageFactory::Pointer msgFactory = this->m_IGTLDevice->GetMessageFactory(); //get the available commands as std::list std::list commandsList_ = msgFactory->GetAvailableMessageRequestTypes(); //create a string list to convert the std::list this->m_Controls->commandsComboBox->clear(); while ( commandsList_.size() ) { //fill the combo box with life this->m_Controls->commandsComboBox->addItem( QString::fromStdString(commandsList_.front())); commandsList_.pop_front(); } } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h index 05b541d54d..f3de5f7eb7 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.h @@ -1,139 +1,144 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKIGTLDeviceSourceMANAGEMENTWIDGET_H #define QMITKIGTLDeviceSourceMANAGEMENTWIDGET_H //QT headers #include #include //mitk headers #include "MitkOpenIGTLinkUIExports.h" #include "mitkIGTLDeviceSource.h" #include "mitkIGTLClient.h" #include "mitkDataStorage.h" //itk #include //ui header #include "ui_QmitkIGTLDeviceSourceManagementWidgetControls.h" /** Documentation: * \brief An object of this class offers an UI to manage OpenIGTLink Device * Sources and OpenIGTLink Devices. * * * \ingroup OpenIGTLinkUI */ class MITK_OPENIGTLINKUI_EXPORT QmitkIGTLDeviceSourceManagementWidget : public QWidget { Q_OBJECT public: static const std::string VIEW_ID; /** Loads a source to the widget. The old source is dropped, so be careful, * if the source is not saved somewhere else it might be lost. You might * want to ask the user if he wants to save the changes before calling this * method. * @param sourceToLoad This source will be loaded and might be modified * by the user. */ void LoadSource(mitk::IGTLDeviceSource::Pointer sourceToLoad); QmitkIGTLDeviceSourceManagementWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); ~QmitkIGTLDeviceSourceManagementWidget(); /// \brief Is called when the current device received a message void OnMessageReceived(itk::Object* caller, const itk::EventObject&); /// \brief Is called when the current device received a command void OnCommandReceived(itk::Object* caller, const itk::EventObject&); signals: /** This signal is emmited if a new source was added by the widget itself, * e.g. because a source was loaded. * @param newSource Holds the new source which was added. * @param sourceName Name of the new source */ void NewSourceAdded(mitk::IGTLDeviceSource::Pointer newSource, std::string sourceName); protected slots: void OnConnect(); void OnPortChanged(); void OnHostnameChanged(); void OnCommandChanged(const QString& curCommand); void OnSendMessage(); void OnSendCommand(); + /** + * \brief Enables/Disables the buffering of incoming messages + */ + void OnBufferIncomingMessages(int state); + protected: /// \brief Fills the commands combo box with available commands void FillCommandsComboBox(); /// \brief Creation of the connections virtual void CreateConnections(); virtual void CreateQtPartControl(QWidget *parent); Ui::QmitkIGTLDeviceSourceManagementWidgetControls* m_Controls; /** @brief holds the OpenIGTLink device */ mitk::IGTLDevice* m_IGTLDevice; /** @brief holds the IGTLDeviceSource we are working with. */ mitk::IGTLDeviceSource::Pointer m_IGTLDeviceSource; /** @brief shows if we are in edit mode, if not we create new source. */ bool m_edit; igtl::MessageBase::Pointer m_CurrentCommand; /** mutex to control access to m_State */ // itk::FastMutexLock::Pointer m_OutputMutex; /** @brief a string stream used for logging */ // std::stringstream m_Output; /** @brief flag to indicate if the output has to be updated */ // bool m_OutputChanged; /** @brief flag to indicate if the IGTL device is a client or a server */ bool m_IsClient; /** @brief a string stream used for logging */ // QTimer m_UpdateLoggingWindowTimer; unsigned long m_MessageReceivedObserverTag; unsigned long m_CommandReceivedObserverTag; itk::MemberCommand< QmitkIGTLDeviceSourceManagementWidget >::Pointer m_MessageReceivedCommand; //############## private help methods ####################### void MessageBox(std::string s); // void UpdateToolTable(); void DisableSourceControls(); void EnableSourceControls(); }; #endif diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui index 32f608bee7..287c61cbae 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui @@ -1,240 +1,283 @@ QmitkIGTLDeviceSourceManagementWidgetControls 0 0 443 781 Form + + The selected IGTL device source + Selected IGTL Device Source: <none> Setup Connection + + + + false + + + Enable this checkbox to log the send and receive message events + + + Log Send and Receive Messages + + + Port Server-IP false + + Enter the port number of the host + 18944 5 true Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Port false + + Enter the IP address of the host + 127.0.0.1 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - Do image processing + Connect with the host/Start server Connect false false false false false - - + + false + + If this checkbox is set the device stores all incoming messages in the queue. If it is not set it always overwrites the current value. + - Log Send and Receive Messages + Buffer Incoming Messages + + + true Send String Messages false + + Enter the string to be sent + false + + Sends a message with the given string to the connected device + Send String Send Command Messages false Choose Command Message Type 0 0 + + Frames per second + FPS: false 0 0 + + Set the frames per second of the stream + 10 false + + Send the command + Send Command Qt::Vertical 20 40