diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.cpp b/Modules/OpenIGTLink/mitkIGTLDevice.cpp index 0ba6496f3c..f1464dbd6e 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.cpp +++ b/Modules/OpenIGTLink/mitkIGTLDevice.cpp @@ -1,443 +1,370 @@ /*=================================================================== 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 -typedef itk::MutexLockHolder MutexLockHolder; +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_StopCommunication(false), m_PortNumber(-1), m_MultiThreader(NULL), m_ThreadID(0), m_Name("Unspecified Device") { 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_Queue = mitk::IGTLMessageQueue::New(); + m_SendQueue = mitk::IGTLMessageQueue::New(); + m_ReceiveQueue = 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(); } -//mitk::IGTLDeviceData mitk::IGTLDevice::GetData() const{ -// return m_Data; -//} - - -//void mitk::IGTLDevice::SetData(mitk::IGTLDeviceData data){ -// m_Data = data; -//} - +void mitk::IGTLDevice::SendMessage(igtl::MessageBase::Pointer msg) +{ + //add the message to the queue + m_SendQueue->PushMessage(msg); +} -bool mitk::IGTLDevice::SendMessage(igtl::MessageBase::Pointer msg) +bool mitk::IGTLDevice::SendMessagePrivate(igtl::MessageBase::Pointer msg) { //check the input message if ( msg.IsNull() ) { MITK_ERROR("IGTLDevice") << "Could not send message because message is not " "valid. Please check."; return false; } // Pack (serialize) and send msg->Pack(); int sendSuccess = this->m_Socket->Send(msg->GetPackPointer(), msg->GetPackSize()); if (sendSuccess) return true; else return false; } -//mitk::NDIErrorCode mitk::IGTLDevice::Receive(std::string* answer, unsigned int numberOfBytes) -//{ -// if (answer == NULL) -// return SERIALRECEIVEERROR; - -// MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex -// long returnvalue = m_SerialCommunication->Receive(*answer, numberOfBytes); // never read more bytes than the device has send, the function will block until enough bytes are send... - -// if (returnvalue == 0) -// return SERIALRECEIVEERROR; -// else -// return NDIOKAY; -//} - bool mitk::IGTLDevice::TestConnection() { -// if (this->GetState() != Setup) -// { -// return mitk::TrackingSystemNotSpecified; -// } - -// m_SerialCommunication = mitk::SerialCommunication::New(); -// //m_DeviceProtocol = mitk::NDIProtocol::New(); -// //m_DeviceProtocol->SetTrackingDevice(this); -// //m_DeviceProtocol->UseCRCOn(); -// /* init local com port to standard com settings for a NDI tracking device: -// 9600 baud, 8 data bits, no parity, 1 stop bit, no hardware handshake -// */ -// if (m_DeviceName.empty()) -// m_SerialCommunication->SetPortNumber(m_PortNumber); -// else -// m_SerialCommunication->SetDeviceName(m_DeviceName); - -// m_SerialCommunication->SetBaudRate(mitk::SerialCommunication::BaudRate9600); -// m_SerialCommunication->SetDataBits(mitk::SerialCommunication::DataBits8); -// m_SerialCommunication->SetParity(mitk::SerialCommunication::None); -// m_SerialCommunication->SetStopBits(mitk::SerialCommunication::StopBits1); -// m_SerialCommunication->SetSendTimeout(5000); -// m_SerialCommunication->SetReceiveTimeout(5000); -// if (m_SerialCommunication->OpenConnection() == 0) // error -// { -// m_SerialCommunication = NULL; -// return mitk::TrackingSystemNotSpecified; -// } - -// /* Reset Tracking device by sending a serial break for 500ms */ -// m_SerialCommunication->SendBreak(400); - -// /* Read answer from tracking device (RESETBE6F) */ -// static const std::string reset("RESETBE6F\r"); -// std::string answer = ""; -// this->Receive(&answer, reset.length()); // read answer (should be RESETBE6F) -// this->ClearReceiveBuffer(); // flush the receive buffer of all remaining data (carriage return, strings other than reset -// if (reset.compare(answer) != 0) // check for RESETBE6F -// { -// m_SerialCommunication->CloseConnection(); -// m_SerialCommunication = NULL; -// mitkThrowException(mitk::IGTHardwareException) << "Hardware Reset of tracking device did not work"; -// } - -// /* Now the tracking device is reset, start initialization */ -// NDIErrorCode returnvalue; - -// /* initialize the tracking device */ -// //returnvalue = m_DeviceProtocol->INIT(); -// //if (returnvalue != NDIOKAY) -// //{ -// // this->SetErrorMessage("Could not initialize the tracking device"); -// // return mitk::TrackingSystemNotSpecified; -// //} - - -// mitk::TrackingDeviceType deviceType; -// returnvalue = m_DeviceProtocol->VER(deviceType); -// if ((returnvalue != NDIOKAY) || (deviceType == mitk::TrackingSystemNotSpecified)) -// { -// m_SerialCommunication = NULL; -// return mitk::TrackingSystemNotSpecified; -// } -// m_SerialCommunication = NULL; -// return deviceType; + return true; } - -ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartCommunication(void* pInfoStruct) +void mitk::IGTLDevice::Receive() { - /* extract this pointer from Thread Info structure */ - struct itk::MultiThreader::ThreadInfoStruct * pInfo = - (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; - if (pInfo == NULL) + // 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 = + m_Socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(),1); + + if(r == 0) { - return ITK_THREAD_RETURN_VALUE; + //this->StopCommunication(); + // an error was received, therefor the communication must be stopped + m_StopCommunicationMutex->Lock(); + m_StopCommunication = true; + m_StopCommunicationMutex->Unlock(); } - if (pInfo->UserData == NULL) + else if (r == headerMsg->GetPackSize()) { - return ITK_THREAD_RETURN_VALUE; + // 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); + + //Create a message buffer to receive transform data + igtl::MessageBase::Pointer curMessage; + curMessage = m_MessageFactory->CreateInstance(headerMsg); + curMessage->SetMessageHeader(headerMsg); + curMessage->AllocatePack(); + + // Receive transform data from the socket + int receiveCheck = 0; + receiveCheck = m_Socket->Receive(curMessage->GetPackBodyPointer(), + curMessage->GetPackBodySize()); + + if ( receiveCheck > 0 ) + { + int c = curMessage->Unpack(1); + if ( !(c & igtl::MessageHeader::UNPACK_BODY) ) + { + mitkThrow() << "crc error"; + } + + //push the current message into the queue + m_ReceiveQueue->PushMessage(curMessage); + } + else + { + MITK_ERROR("IGTLDevice") << "Received a valid header but could not " + << "read the whole message."; + } + } } - IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; - if (igtlDevice != NULL) + else { - igtlDevice->RunCommunication(); + //Message size information and actual data size don't match. } - igtlDevice->m_ThreadID = 0; // erase thread id because thread will end. - return ITK_THREAD_RETURN_VALUE; } +void mitk::IGTLDevice::Send() +{ + igtl::MessageBase::Pointer curMessage; + + //get the latest message from the queue + curMessage = m_SendQueue->PullMessage(); + + // there is no message => return + if ( curMessage.IsNull() ) + return; + + if ( this->SendMessagePrivate(curMessage.GetPointer()) ) + { + MITK_INFO("IGTLDevice") << "Successfully sent the message."; + } + else + { + MITK_ERROR("IGTLDevice") << "Could not send the message."; + } +} + + 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)) { - //POLLLING - // Create a message buffer to receive header - igtl::MessageHeader::Pointer headerMsg; - headerMsg = igtl::MessageHeader::New(); - - // Initialize receive buffer - headerMsg->InitPack(); + // Check if there is something to receive and store it in the message queue + this->Receive(); - // Receive generic header from the socket -// this->m_SocketMutex->Lock(); - int r = - m_Socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(),1); -// this->m_SocketMutex->Unlock(); + // Check if there is something to send + this->Send(); - if(r == 0) - { - //this->StopCommunication(); - // an error was received, therefor the communication must be stopped - m_StopCommunicationMutex->Lock(); - m_StopCommunication = true; - m_StopCommunicationMutex->Unlock(); - } - 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); - - //check for invalid timestamps -// if(sec != 0) - { - std::cerr << "Time stamp: " - << sec << "." - << nanosec << std::endl; - - std::cerr << "Dev type and name: " << headerMsg->GetDeviceType() << " " - << headerMsg->GetDeviceName() << std::endl; - - headerMsg->Print(std::cout); - - //Create a message buffer to receive transform data - /*igtl::MessageBase::Pointer curMessage; - curMessage = igtl::MessageBase::New(); - curMessage->SetMessageHeader(headerMsg); - curMessage->AllocatePack();*/ - - //Create a message buffer to receive transform data - igtl::MessageBase::Pointer curMessage; - curMessage = m_MessageFactory->CreateInstance(headerMsg); - curMessage->SetMessageHeader(headerMsg); - curMessage->AllocatePack(); - - // Receive transform data from the socket - int receiveCheck = 0; - receiveCheck = m_Socket->Receive(curMessage->GetPackBodyPointer(), - curMessage->GetPackBodySize()); - - if ( receiveCheck > 0 ) - { - int c = curMessage->Unpack(1); - if ( !(c & igtl::MessageHeader::UNPACK_BODY) ) - { - mitkThrow() << "crc error"; - } - - //copy the current message into the latest message member -// m_LatestMessageMutex->Lock(); - m_Queue->PushMessage(curMessage); -// m_LatestMessage = m_MessageFactory->Clone(curMessage); -// m_LatestMessageMutex->Unlock(); - } - else - { - MITK_ERROR("IGTLDevice") << "Received a valid header but could not " - << "read the whole message."; - } - } - } - } - else - { - //Message size information and actual data size don't match. - } - -// m_MarkerPointsMutex->Lock(); // lock points data structure -// returnvalue = this->m_DeviceProtocol->POS3D(&m_MarkerPoints); // update points data structure with new position data from tracking device -// m_MarkerPointsMutex->Unlock(); -// if (!((returnvalue == NDIOKAY) || (returnvalue == NDICRCERROR) || (returnvalue == NDICRCDOESNOTMATCH))) // right now, do not stop on crc errors -// { -// std::cout << "Error in POS3D: could not read data. Possibly no markers present." << std::endl; -// } /* 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; - this->SetState(Running); // go to mode Running + // 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(); -// //init before closing to force the field generator from aurora to switch itself off -// m_DeviceProtocol->INIT(); -// /* close the serial connection */ -// m_SerialCommunication->CloseConnection(); -// /* invalidate all tools */ -// this->InvalidateAll(); + /* return to setup mode */ this->SetState(Setup); // m_SerialCommunication = NULL; return true; } igtl::MessageBase::Pointer mitk::IGTLDevice::GetLatestMessage() { //copy the latest message into the given msg -// m_LatestMessageMutex->Lock(); -// igtl::MessageBase::Pointer msg = -// this->m_MessageFactory->Clone(m_LatestMessage); -// m_LatestMessageMutex->Unlock(); -// return msg; - return this->m_Queue->PullMessage(); +// m_ReceiveQueueMutex->Lock(); + igtl::MessageBase::Pointer msg = this->m_ReceiveQueue->PullMessage(); +// m_ReceiveQueueMutex->Unlock(); + return msg; +} + +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 14f77f6bce..1b8183bd25 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.h +++ b/Modules/OpenIGTLink/mitkIGTLDevice.h @@ -1,210 +1,234 @@ /*=================================================================== 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 #include "itkObject.h" #include "mitkCommon.h" #include "itkFastMutexLock.h" #include //#include #include "igtlSocket.h" #include "igtlMessageBase.h" #include "igtlTransformMessage.h" #include "mitkIGTLMessageFactory.h" #include "mitkIGTLMessageQueue.h" namespace mitk { /**Documentation * \brief Interface for all Open IGT Link Devices * * Defines the methods that are common for all devices using Open IGT Link. * */ 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 */ 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 */ 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 */ virtual bool StopCommunication(); bool StartCommunication(); void RunCommunication(); /** * \brief Sends a message via the open IGT Link. * * This may only be called after the connection to the device has been - * established with a call to OpenConnection() (E.g. object is in Ready - * mode). This will change the object state from Ready to Running + * established with a call to OpenConnection(). Note that the message + * is not send directly. This method just adds it to the send queue. */ - bool SendMessage(igtl::MessageBase::Pointer msg); + void SendMessage(igtl::MessageBase::Pointer msg); /** * \brief return current object state (Setup, Ready or Running) */ IGTLDeviceState GetState() const; /** * \brief Returns the latest 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 */ igtl::MessageBase::Pointer GetLatestMessage(); /** * \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 static start method for the tracking thread. */ static ITK_THREAD_RETURN_TYPE ThreadStartCommunication(void* data); /** * \brief TestConnection() tries to connect to a IGTL server on the current * ip and port * * \todo check this description * * 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 * if no device is available on that ip/port. * @throw mitk::IGTHardwareException Throws an exception if there are errors * while connecting to the device. */ virtual bool TestConnection(); protected: + /** + * \brief Sends a message via the open IGT Link. + * + * This may only be called after the connection to the device has been + * established with a call to OpenConnection() + */ + bool SendMessagePrivate(igtl::MessageBase::Pointer msg); + + + /** + * \brief Call this method to receive a message. The message will be saved + * in the queue + */ + void Receive(); + + /** + * \brief Call this method to send a message. The message will be read from + * the queue + */ + void Send(); /** * \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 */ itk::FastMutexLock::Pointer m_StopCommunicationMutex; /** mutex to manage control flow of StopTracking() */ 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_LatestMessage */ -// itk::FastMutexLock::Pointer m_LatestMessageMutex; + /** 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 queue */ - mitk::IGTLMessageQueue::Pointer m_Queue; + /** The message receive queue */ + mitk::IGTLMessageQueue::Pointer m_ReceiveQueue; + /** The message send queue */ + mitk::IGTLMessageQueue::Pointer m_SendQueue; /** the latest received message */ 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 }; } // namespace mitk #endif /* MITKIGTLDEVICE_H */ diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp index 443e7ee996..9c89559147 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp @@ -1,415 +1,414 @@ /*=================================================================== 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 //qt headers #include #include #include //igtl #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_Controls = 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); } - //Disable certain controls in the beginning, because there is no storage to edit - m_Controls->butSend->setEnabled(false); - // 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->butConnectWithServer, 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())); } // //main widget page: // connect( (QObject*)(m_Controls->m_AddTool), SIGNAL(clicked()), this, SLOT(OnAddTool()) ); // connect( (QObject*)(m_Controls->m_DeleteTool), SIGNAL(clicked()), this, SLOT(OnDeleteTool()) ); // connect( (QObject*)(m_Controls->m_EditTool), SIGNAL(clicked()), this, SLOT(OnEditTool()) ); // connect( (QObject*)(m_Controls->m_LoadStorage), SIGNAL(clicked()), this, SLOT(OnLoadStorage()) ); // connect( (QObject*)(m_Controls->m_SaveStorage), SIGNAL(clicked()), this, SLOT(OnSaveStorage()) ); // connect( (QObject*)(m_Controls->m_LoadTool), SIGNAL(clicked()), this, SLOT(OnLoadTool()) ); // connect( (QObject*)(m_Controls->m_SaveTool), SIGNAL(clicked()), this, SLOT(OnSaveTool()) ); // connect( (QObject*)(m_Controls->m_CreateNewStorage), SIGNAL(clicked()), this, SLOT(OnCreateStorage()) ); // //widget page "add tool": // connect( (QObject*)(m_Controls->m_ToolCreationWidget), SIGNAL(Canceled()), this, SLOT(OnAddToolCancel()) ); // connect( (QObject*)(m_Controls->m_ToolCreationWidget), SIGNAL(NavigationToolFinished()), this, SLOT(OnAddToolSave()) ); } //void QmitkIGTLDeviceSourceManagementWidget::OnLoadTool() //{ // if(m_IGTLDeviceSource->isLocked()) // { // MessageBox("Storage is locked, cannot modify it. Maybe the tracking device which uses this storage is connected. If you want to modify the storage please disconnect the device first."); // return; // } // mitk::NavigationToolReader::Pointer myReader = mitk::NavigationToolReader::New(); // std::string filename = QFileDialog::getOpenFileName(NULL,tr("Add Navigation Tool"), "/", "*.IGTTool").toAscii().data(); // if (filename == "") return; // mitk::NavigationTool::Pointer readTool = myReader->DoRead(filename); // if (readTool.IsNull()) MessageBox("Error: " + myReader->GetErrorMessage()); // else // { // if (!m_IGTLDeviceSource->AddTool(readTool)) // { // MessageBox("Error: Can't add tool!"); // m_DataStorage->Remove(readTool->GetDataNode()); // } // UpdateToolTable(); // } //} //void QmitkIGTLDeviceSourceManagementWidget::OnSaveTool() //{ // //if no item is selected, show error message: // if (m_Controls->m_ToolList->currentItem() == NULL) {MessageBox("Error: Please select tool first!");return;} // mitk::NavigationToolWriter::Pointer myWriter = mitk::NavigationToolWriter::New(); // std::string filename = QFileDialog::getSaveFileName(NULL,tr("Save Navigation Tool"), "/", "*.IGTTool").toAscii().data(); // if (filename == "") return; // if (!myWriter->DoWrite(filename,m_IGTLDeviceSource->GetTool(m_Controls->m_ToolList->currentIndex().row()))) // MessageBox("Error: "+ myWriter->GetErrorMessage()); //} void QmitkIGTLDeviceSourceManagementWidget::Initialize( mitk::DataStorage* /*dataStorage*/) { // m_DataStorage = dataStorage; // m_Controls->m_ToolCreationWidget->Initialize(m_DataStorage,"Tool0"); } void QmitkIGTLDeviceSourceManagementWidget::LoadSource( mitk::IGTLDeviceSource::Pointer sourceToLoad) { if(sourceToLoad.IsNotNull()) { this->m_IGTLDeviceSource = sourceToLoad; this->m_IGTLClient = (mitk::IGTLClient*)this->m_IGTLDeviceSource->GetIGTLDevice(); m_Controls->selectedSourceLabel->setText(m_IGTLDeviceSource->GetName().c_str()); EnableSourceControls(); } else { m_IGTLDeviceSource = NULL; DisableSourceControls(); } // UpdateToolTable(); } ////################################################################################## ////############################## slots: main widget ################################ ////################################################################################## //void QmitkIGTLDeviceSourceManagementWidget::OnAddTool() // { // if(m_IGTLDeviceSource->isLocked()) // { // MessageBox("Storage is locked, cannot modify it. Maybe the tracking device which uses this storage is connected. If you want to modify the storage please disconnect the device first."); // return; // } // QString defaultIdentifier = "NavigationTool#"+QString::number(m_IGTLDeviceSource->GetToolCount()); // m_Controls->m_ToolCreationWidget->Initialize(m_DataStorage,defaultIdentifier.toStdString()); // m_edit = false; // m_Controls->m_MainWidgets->setCurrentIndex(1); // } //void QmitkIGTLDeviceSourceManagementWidget::OnDeleteTool() // { // //first: some checks // if(m_IGTLDeviceSource->isLocked()) // { // MessageBox("Storage is locked, cannot modify it. Maybe the tracking device which uses this storage is connected. If you want to modify the storage please disconnect the device first."); // return; // } // else if (m_Controls->m_ToolList->currentItem() == NULL) //if no item is selected, show error message: // { // MessageBox("Error: Please select tool first!"); // return; // } // m_DataStorage->Remove(m_IGTLDeviceSource->GetTool(m_Controls->m_ToolList->currentIndex().row())->GetDataNode()); // m_IGTLDeviceSource->DeleteTool(m_Controls->m_ToolList->currentIndex().row()); // UpdateToolTable(); // } //void QmitkIGTLDeviceSourceManagementWidget::OnEditTool() // { // if(m_IGTLDeviceSource->isLocked()) // { // MessageBox("Storage is locked, cannot modify it. Maybe the tracking device which uses this storage is connected. If you want to modify the storage please disconnect the device first."); // return; // } // else if (m_Controls->m_ToolList->currentItem() == NULL) //if no item is selected, show error message: // { // MessageBox("Error: Please select tool first!"); // return; // } // mitk::NavigationTool::Pointer selectedTool = m_IGTLDeviceSource->GetTool(m_Controls->m_ToolList->currentIndex().row()); // m_Controls->m_ToolCreationWidget->SetDefaultData(selectedTool); // m_edit = true; // m_Controls->m_MainWidgets->setCurrentIndex(1); // } //void QmitkIGTLDeviceSourceManagementWidget::OnCreateStorage() // { // QString storageName = QInputDialog::getText(NULL,"Storage Name","Name of the new tool storage:"); // if (storageName.isNull()) return; // m_IGTLDeviceSource = mitk::NavigationToolStorage::New(this->m_DataStorage); // m_IGTLDeviceSource->SetName(storageName.toStdString()); // m_Controls->m_StorageName->setText(m_IGTLDeviceSource->GetName().c_str()); // EnableStorageControls(); // emit NewStorageAdded(m_IGTLDeviceSource, storageName.toStdString()); // } //void QmitkIGTLDeviceSourceManagementWidget::OnLoadStorage() // { // mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(m_DataStorage); // std::string filename = QFileDialog::getOpenFileName(NULL, tr("Open Navigation Tool Storage"), "/", tr("IGT Tool Storage (*.IGTToolStorage)")).toStdString(); // if (filename == "") return; // try // { // mitk::NavigationToolStorage::Pointer tempStorage = myDeserializer->Deserialize(filename); // if (tempStorage.IsNull()) MessageBox("Error" + myDeserializer->GetErrorMessage()); // else // { // Poco::Path myPath = Poco::Path(filename.c_str()); // tempStorage->SetName(myPath.getFileName()); //set the filename as name for the storage, so the user can identify it // this->LoadStorage(tempStorage); // emit NewStorageAdded(m_IGTLDeviceSource,myPath.getFileName()); // } // } // catch (const mitk::Exception& exception) // { // MessageBox(exception.GetDescription()); // } // } //void QmitkIGTLDeviceSourceManagementWidget::OnSaveStorage() // { // //read in filename // QString filename = QFileDialog::getSaveFileName(NULL, tr("Save Navigation Tool Storage"), "/", tr("IGT Tool Storage (*.IGTToolStorage)")); // if (filename.isEmpty()) return; //canceled by the user // // add file extension if it wasn't added by the file dialog // if ( filename.right(15) != ".IGTToolStorage" ) { filename += ".IGTToolStorage"; } // //serialize tool storage // mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); // if (!mySerializer->Serialize(filename.toStdString(),m_IGTLDeviceSource)) // { // MessageBox("Error: " + mySerializer->GetErrorMessage()); // return; // } // Poco::Path myPath = Poco::Path(filename.toStdString()); // m_Controls->m_StorageName->setText(QString::fromStdString(myPath.getFileName())); // } ////################################################################################## ////############################## slots: add tool widget ############################ ////################################################################################## //void QmitkIGTLDeviceSourceManagementWidget::OnAddToolSave() // { // mitk::NavigationTool::Pointer newTool = m_Controls->m_ToolCreationWidget->GetCreatedTool(); // if (m_edit) //here we edit a existing tool // { // mitk::NavigationTool::Pointer editedTool = m_IGTLDeviceSource->GetTool(m_Controls->m_ToolList->currentIndex().row()); // editedTool->Graft(newTool); // } // else //here we create a new tool // { // m_IGTLDeviceSource->AddTool(newTool); // } // UpdateToolTable(); // m_Controls->m_MainWidgets->setCurrentIndex(0); // } //void QmitkIGTLDeviceSourceManagementWidget::OnAddToolCancel() // { // m_Controls->m_MainWidgets->setCurrentIndex(0); // } 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->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() { m_Controls->editIP->setEnabled(true); m_Controls->editPort->setEnabled(true); + m_Controls->butConnectWithServer->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->butConnectWithServer->text() == "Connect") { m_IGTLClient->SetPortNumber(m_Controls->editPort->text().toInt()); m_IGTLClient->SetHostname(m_Controls->editIP->text().toStdString()); m_IGTLClient->OpenConnection(); if ( m_IGTLClient->StartCommunication() ) { m_Controls->editIP->setEnabled(false); m_Controls->editPort->setEnabled(false); m_Controls->editSend->setEnabled(true); m_Controls->butSend->setEnabled(true); m_Controls->butConnectWithServer->setText("Disconnect"); } else { MITK_ERROR("OpenIGTLinkExample") << "Could not start a communication with the" "server. Please check the hostname and port."; } // Start(); } else { m_Controls->editIP->setEnabled(true); m_Controls->editPort->setEnabled(true); m_Controls->editSend->setEnabled(false); m_Controls->butSend->setEnabled(false); m_Controls->butConnectWithServer->setText("Connect"); m_IGTLClient->CloseConnection(); } } void QmitkIGTLDeviceSourceManagementWidget::OnPortChanged() { } void QmitkIGTLDeviceSourceManagementWidget::OnHostnameChanged() { } void QmitkIGTLDeviceSourceManagementWidget::OnSendMessage() { std::string toBeSend = m_Controls->editSend->text().toStdString(); igtl::StringMessage::Pointer msg = igtl::StringMessage::New().GetPointer(); msg->SetString(toBeSend); - if ( m_IGTLClient->SendMessage(msg.GetPointer()) ) - { - MITK_INFO("OpenIGTLinkExample") << "Successfully sent the message."; - } - else - { - MITK_ERROR("OpenIGTLinkExample") << "Could not send the message."; - } + m_IGTLClient->SendMessage(msg.GetPointer()); +// if ( m_IGTLClient->SendMessage(msg.GetPointer()) ) +// { +// MITK_INFO("OpenIGTLinkExample") << "Successfully sent the message."; +// } +// else +// { +// MITK_ERROR("OpenIGTLinkExample") << "Could not send the message."; +// } } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui index 176152c0c9..ad3c819d05 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidgetControls.ui @@ -1,141 +1,154 @@ QmitkIGTLDeviceSourceManagementWidgetControls 0 0 443 781 Form Selected IGTL Device Source: <none> Port Server-IP + + false + 18944 5 true Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Port - true + false 127.0.0.1 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + false + Do image processing Connect false false false false false - + + + false + + + + false + Send Qt::Vertical 20 220