diff --git a/CMake/OpenIGTLinkCMakeTests.cmake b/CMake/OpenIGTLinkCMakeTests.cmake index 7c4406be..54447444 100644 --- a/CMake/OpenIGTLinkCMakeTests.cmake +++ b/CMake/OpenIGTLinkCMakeTests.cmake @@ -1,6 +1,7 @@ # See if we need to link the socket library INCLUDE(CheckLibraryExists) INCLUDE(CheckSymbolExists) +INCLUDE(CheckFunctionExists) CHECK_LIBRARY_EXISTS("socket" getsockname "" OpenIGTLink_HAVE_LIBSOCKET) @@ -33,6 +34,10 @@ IF("OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T" MATCHES "^OpenIGTLink_HAVE_GETS ENDIF(OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T) ENDIF("OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T" MATCHES "^OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T$") + +# e.g. Mac OS X Snow Leopard does not have strnlen(). +CHECK_FUNCTION_EXISTS(strnlen OpenIGTLink_HAVE_STRNLEN) + # e.g. IBM BlueGene/L doesn't have SO_REUSEADDR, because "setsockopt is not needed for # BlueGene/L applications" according to the BlueGene/L Application Development handbook CHECK_SYMBOL_EXISTS(SO_REUSEADDR "sys/types.h;sys/socket.h" OpenIGTLink_HAVE_SO_REUSEADDR) diff --git a/CMakeLists.txt b/CMakeLists.txt index 305052ff..371aae27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,8 +9,8 @@ if(COMMAND cmake_policy) #----------------------------------------------------------------------------- # OpenIGTlink version number. SET(OpenIGTLink_VERSION_MAJOR "1") -SET(OpenIGTLink_VERSION_MINOR "9") -SET(OpenIGTLink_VERSION_PATCH "8") +SET(OpenIGTLink_VERSION_MINOR "10") +SET(OpenIGTLink_VERSION_PATCH "10") option(OpenIGTLink_PROTOCOL_VERSION_2 "Build Library for Protocol Version 2" ON) diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index cd86635a..356342bb 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -24,6 +24,9 @@ if (${OpenIGTLink_PROTOCOL_VERSION} STREQUAL "2") String Bind PolyData + Capability + Trajectory + SessionManager ) endif (${OpenIGTLink_PROTOCOL_VERSION} STREQUAL "2") diff --git a/Examples/Capability/CMakeLists.txt b/Examples/Capability/CMakeLists.txt new file mode 100644 index 00000000..dac2a764 --- /dev/null +++ b/Examples/Capability/CMakeLists.txt @@ -0,0 +1,18 @@ +PROJECT(Capability) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(CapabilityClient CapabilityClient.cxx) +TARGET_LINK_LIBRARIES(CapabilityClient OpenIGTLink) + +ADD_EXECUTABLE(CapabilityServer CapabilityServer.cxx) +TARGET_LINK_LIBRARIES(CapabilityServer OpenIGTLink) + + diff --git a/Examples/Capability/CapabilityClient.cxx b/Examples/Capability/CapabilityClient.cxx new file mode 100644 index 00000000..4eb1b883 --- /dev/null +++ b/Examples/Capability/CapabilityClient.cxx @@ -0,0 +1,86 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Sending Capability Messasge + Module: $RCSfile: $ + Language: C++ + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlCapabilityMessage.h" +#include "igtlClientSocket.h" + +#include "igtlTransformMessage.h" +#include "igtlImageMessage.h" +#include "igtlLabelMetaMessage.h" + +// +// Test comment +// + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + int interval = (int) (1000); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Capability Message Class + + igtl::CapabilityMessage::Pointer capabilityMsg; + capabilityMsg = igtl::CapabilityMessage::New(); + capabilityMsg->SetDeviceName("Device"); + + std::vector types; + types.push_back(std::string("TRANSFORM")); + types.push_back(std::string("GET_IMAGE")); + types.push_back(std::string("GET_LBMETA")); + capabilityMsg->SetTypes(types); + capabilityMsg->Pack(); + socket->Send(capabilityMsg->GetPackPointer(), capabilityMsg->GetPackSize()); + //------------------------------------------------------------ + // Close connection + + socket->CloseSocket(); + +} + + diff --git a/Examples/Capability/CapabilityServer.cxx b/Examples/Capability/CapabilityServer.cxx new file mode 100644 index 00000000..15476aeb --- /dev/null +++ b/Examples/Capability/CapabilityServer.cxx @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: Open IGT Link -- Example for Tracker Server Program + Module: $RCSfile: $ + Language: C++ + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlCapabilityMessage.h" +#include "igtlServerSocket.h" + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + int interval = (int) 1000; + + //------------------------------------------------------------ + // Allocate Capability Message Class + + igtl::CapabilityMessage::Pointer capabilityMsg; + capabilityMsg = igtl::CapabilityMessage::New(); + capabilityMsg->SetDeviceName("Device"); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + std::vector types; + types.push_back(std::string("TRANSFORM")); + types.push_back(std::string("GET_IMAGE")); + types.push_back(std::string("GET_LBMETA")); + capabilityMsg->SetTypes(types); + capabilityMsg->Pack(); + socket->Send(capabilityMsg->GetPackPointer(), capabilityMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + + diff --git a/Examples/ImageDatabaseServer/ImageDatabaseServer.cxx b/Examples/ImageDatabaseServer/ImageDatabaseServer.cxx index 72456685..332a6b65 100644 --- a/Examples/ImageDatabaseServer/ImageDatabaseServer.cxx +++ b/Examples/ImageDatabaseServer/ImageDatabaseServer.cxx @@ -25,10 +25,13 @@ #include "igtlMessageHeader.h" #include "igtlImageMessage.h" #include "igtlImageMetaMessage.h" +#include "igtlLabelMetaMessage.h" #include "igtlServerSocket.h" int SendImageMeta(igtl::Socket::Pointer& socket, const char* name); +int SendLabelMeta(igtl::Socket::Pointer& socket, const char* name); int SendImage(igtl::Socket::Pointer& socket, const char* name, const char* filedir); +int SendLabel(igtl::Socket::Pointer& socket, const char* name, const char* filedir); int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i); int main(int argc, char* argv[]) @@ -107,6 +110,10 @@ int main(int argc, char* argv[]) //socket->Skip(headerMsg->GetBodySizeToRead(), 0); SendImageMeta(socket, headerMsg->GetDeviceName()); } + else if (strcmp(headerMsg->GetDeviceType(), "GET_LBMETA") == 0) + { + SendLabelMeta(socket, headerMsg->GetDeviceName()); + } else if (strcmp(headerMsg->GetDeviceType(), "GET_IMAGE") == 0) { SendImage(socket, headerMsg->GetDeviceName(), filedir); @@ -209,6 +216,62 @@ int SendImageMeta(igtl::Socket::Pointer& socket, const char* name) } +int SendLabelMeta(igtl::Socket::Pointer& socket, const char* name) +{ + //------------------------------------------------------------ + // Allocate Status Message Class + + igtl::LabelMetaMessage::Pointer lbMetaMsg; + lbMetaMsg = igtl::LabelMetaMessage::New(); + // NOTE: the server should send a message with the same device name + // as the received query message. + lbMetaMsg->SetDeviceName(name); + + //--------------------------- + // Create 1st meta data + igtl::LabelMetaElement::Pointer lbMeta0; + lbMeta0 = igtl::LabelMetaElement::New(); + lbMeta0->SetName("LABEL_DESCRIPTION_0"); + lbMeta0->SetDeviceName("LABEL_0"); + lbMeta0->SetOwner("IMAGE_0"); + lbMeta0->SetSize(512, 512, 64); + + //--------------------------- + // Create 2nd meta data + igtl::LabelMetaElement::Pointer lbMeta1; + lbMeta1 = igtl::LabelMetaElement::New(); + lbMeta1->SetName("LABEL_DESCRIPTION_1"); + lbMeta1->SetDeviceName("LABEL_1"); + lbMeta1->SetOwner("IMAGE_1"); + + lbMeta1->SetSize(256, 128, 32); + + //--------------------------- + // Create 3rd meta data + igtl::LabelMetaElement::Pointer lbMeta2; + lbMeta2 = igtl::LabelMetaElement::New(); + lbMeta2->SetName("LABEL_DESCRIPTION_2"); + lbMeta2->SetDeviceName("LABEL_2"); + lbMeta2->SetOwner("IMAGE_2"); + lbMeta2->SetSize(256, 256, 32); + + lbMetaMsg->AddLabelMetaElement(lbMeta0); + lbMetaMsg->AddLabelMetaElement(lbMeta1); + lbMetaMsg->AddLabelMetaElement(lbMeta2); + + lbMetaMsg->Pack(); + std::cerr << "Size of pack: " << lbMetaMsg->GetPackSize() << std::endl; + std::cerr << "Name of type: " << lbMetaMsg->GetDeviceType() << std::endl; + std::cerr << "Sending a LBMETA message..." << std::endl; + + socket->Send(lbMetaMsg->GetPackPointer(), lbMetaMsg->GetPackSize()); + + return 1; + +} + + + int SendImage(igtl::Socket::Pointer& socket, const char* name, const char* filedir) { int index = 0; @@ -225,6 +288,18 @@ int SendImage(igtl::Socket::Pointer& socket, const char* name, const char* filed { index = 3; } + if (strcmp(name, "LABEL_0") == 0) + { + index = 4; + } + else if (strcmp(name, "LABEL_1") == 0) + { + index = 5; + } + else if (strcmp(name, "LABEL_2") == 0) + { + index = 6; + } if (index > 0) { @@ -268,7 +343,6 @@ int SendImage(igtl::Socket::Pointer& socket, const char* name, const char* filed } - //------------------------------------------------------------ // Function to read test image data int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i) @@ -276,7 +350,7 @@ int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i) //------------------------------------------------------------ // Check if image index is in the range - if (i < 0 || i >= 5) + if (i < 0 || i >= 7) { std::cerr << "Image index is invalid." << std::endl; return 0; diff --git a/Examples/Point/CMakeLists.txt b/Examples/Point/CMakeLists.txt index 672a1119..08628718 100644 --- a/Examples/Point/CMakeLists.txt +++ b/Examples/Point/CMakeLists.txt @@ -15,3 +15,6 @@ TARGET_LINK_LIBRARIES(PointClient OpenIGTLink) ADD_EXECUTABLE(PointServer PointServer.cxx) TARGET_LINK_LIBRARIES(PointServer OpenIGTLink) +ADD_EXECUTABLE(PointListServer PointListServer.cxx) +TARGET_LINK_LIBRARIES(PointListServer OpenIGTLink) + diff --git a/Examples/Point/PointListServer.cxx b/Examples/Point/PointListServer.cxx new file mode 100644 index 00000000..0209f93b --- /dev/null +++ b/Examples/Point/PointListServer.cxx @@ -0,0 +1,227 @@ +/*========================================================================= + + Program: Open IGT Link -- Example for Image Meta Data Server + Module: $RCSfile: $ + Language: C++ + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlPointMessage.h" +#include "igtlServerSocket.h" + +using std::ifstream; +using std::stringstream; +using std::cerr; + +typedef struct { + double x; + double y; + double z; +} Point; + +typedef std::vector PointList; + +int SendPointList(igtl::Socket::Pointer& socket, const char *devicename, PointList points); +PointList DefaultPointList(); +PointList ReadPointList(char* ); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + PointList pointlist; + + if (argc < 2 || argc > 3) + { + // If not correct, print usage + std::cerr << "Sends OpenIGTLink point list upon POINT_GET request(s)" << std::endl; + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : [optional] file name, wherein each line contains 3 points to send" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + if (argc == 2) // check number of arguments + pointlist = DefaultPointList(); + else if (argc == 3) + { + char* filename = argv[2]; + pointlist = ReadPointList(filename); + } + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + int rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize()); + if (rs == 0) + { + socket->CloseSocket(); + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + std::cerr << "Receiving a message: " << std::endl; + std::cerr << " Device Type: \"" << headerMsg->GetDeviceType() << "\"" << std::endl; + std::cerr << " Device Name: \"" << headerMsg->GetDeviceName() << "\"" << std::endl; + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "GET_POINT") == 0) + { + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + SendPointList(socket, headerMsg->GetDeviceName(), pointlist); + } + else + { + // if the data type is unknown, skip reading. + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + socket->CloseSocket(); +} + + +int SendPointList(igtl::Socket::Pointer& socket, const char* name, PointList points) +{ + std::cout << "Sending PointList" << std::endl; + //------------------------------------------------------------ + // Allocate Point Message Class + igtl::PointMessage::Pointer pointMsg; + pointMsg = igtl::PointMessage::New(); + pointMsg->SetDeviceName("PointSender"); + + //--------------------------- + // Create a point message + int i = 0; + PointList::iterator pt_iter; + for (pt_iter = points.begin(); + pt_iter != points.end(); + ++pt_iter) + { + igtl::PointElement::Pointer point; + point = igtl::PointElement::New(); + stringstream pt_name; + pt_name << "POINT_" << i; + + point->SetName(pt_name.str().c_str()); + point->SetGroupName("GROUP_0"); + point->SetRGBA(0x00, 0x00, 0xFF, 0xFF); + point->SetPosition(pt_iter->x, pt_iter->y, pt_iter->z); + point->SetRadius(75.0); + point->SetOwner("IMAGE_0"); + + //--------------------------- + // Pack into the point message + pointMsg->AddPointElement(point); + i++; + } + pointMsg->Pack(); + + //--------------------------- + // Send + socket->Send(pointMsg->GetPackPointer(), pointMsg->GetPackSize()); + + return 1; +} + +//------------------------------------------------------------ +// Function to create default point list +PointList DefaultPointList() +{ + PointList points; + Point pt1 = {10.0, 20.0, 30.0}; + Point pt2 = {40.0, 50.0, 60.0}; + Point pt3 = {70.0, 80.0, 90.0}; + points.push_back(pt1); + points.push_back(pt2); + points.push_back(pt3); + return points; +} + + +//------------------------------------------------------------ +// Function to read test point data +PointList ReadPointList(char* filename) +{ + PointList points; + + //------------------------------------------------------------ + // Load point list from file + // file format is x y z\n + ifstream f_in(filename); + std::string line; + if (!f_in.is_open()) + { + std::cerr << "Error opening file: " << filename << std::endl; + exit(0); + } + + Point pt; + while ( f_in >> pt.x >> pt.y >> pt.z ) + points.push_back(pt); + + std::cerr << "Read: " << points.size() << " points from file." << std::endl; + return points; +} diff --git a/Examples/Receiver/ReceiveClient.cxx b/Examples/Receiver/ReceiveClient.cxx index 5882f523..56e58922 100644 --- a/Examples/Receiver/ReceiveClient.cxx +++ b/Examples/Receiver/ReceiveClient.cxx @@ -30,9 +30,11 @@ #if OpenIGTLink_PROTOCOL_VERSION >= 2 #include "igtlPointMessage.h" +#include "igtlTrajectoryMessage.h" #include "igtlStringMessage.h" #include "igtlTrackingDataMessage.h" #include "igtlQuaternionTrackingDataMessage.h" +#include "igtlCapabilityMessage.h" #endif // OpenIGTLink_PROTOCOL_VERSION >= 2 int ReceiveTransform(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); @@ -42,9 +44,11 @@ int ReceiveStatus(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); #if OpenIGTLink_PROTOCOL_VERSION >= 2 int ReceivePoint(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); + int ReceiveTrajectory(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); int ReceiveString(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); int ReceiveTrackingData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); int ReceiveQuaternionTrackingData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); + int ReceiveCapability(igtl::Socket * socket, igtl::MessageHeader * header); #endif //OpenIGTLink_PROTOCOL_VERSION >= 2 int main(int argc, char* argv[]) @@ -145,6 +149,10 @@ int main(int argc, char* argv[]) { ReceivePoint(socket, headerMsg); } + else if (strcmp(headerMsg->GetDeviceType(), "TRAJ") == 0) + { + ReceiveTrajectory(socket, headerMsg); + } else if (strcmp(headerMsg->GetDeviceType(), "STRING") == 0) { ReceiveString(socket, headerMsg); @@ -157,6 +165,10 @@ int main(int argc, char* argv[]) { ReceiveQuaternionTrackingData(socket, headerMsg); } + else if (strcmp(headerMsg->GetDeviceType(), "CAPABILITY") == 0) + { + ReceiveCapability(socket, headerMsg);; + } #endif //OpenIGTLink_PROTOCOL_VERSION >= 2 else { @@ -368,6 +380,55 @@ int ReceivePoint(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) return 1; } +int ReceiveTrajectory(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving TRAJECTORY data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::TrajectoryMessage::Pointer trajectoryMsg; + trajectoryMsg = igtl::TrajectoryMessage::New(); + trajectoryMsg->SetMessageHeader(header); + trajectoryMsg->AllocatePack(); + + // Receive transform data from the socket + socket->Receive(trajectoryMsg->GetPackBodyPointer(), trajectoryMsg->GetPackBodySize()); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = trajectoryMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = trajectoryMsg->GetNumberOfTrajectoryElement(); + for (int i = 0; i < nElements; i ++) + { + igtl::TrajectoryElement::Pointer trajectoryElement; + trajectoryMsg->GetTrajectoryElement(i, trajectoryElement); + + igtlUint8 rgba[4]; + trajectoryElement->GetRGBA(rgba); + + igtlFloat32 entry[3]; + igtlFloat32 target[3]; + trajectoryElement->GetEntryPosition(entry); + trajectoryElement->GetTargetPosition(target); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << trajectoryElement->GetName() << std::endl; + std::cerr << " GroupName : " << trajectoryElement->GetGroupName() << std::endl; + std::cerr << " RGBA : ( " << (int)rgba[0] << ", " << (int)rgba[1] << ", " << (int)rgba[2] << ", " << (int)rgba[3] << " )" << std::endl; + std::cerr << " Entry Pt : ( " << std::fixed << entry[0] << ", " << entry[1] << ", " << entry[2] << " )" << std::endl; + std::cerr << " Target Pt : ( " << std::fixed << target[0] << ", " << target[1] << ", " << target[2] << " )" << std::endl; + std::cerr << " Radius : " << std::fixed << trajectoryElement->GetRadius() << std::endl; + std::cerr << " Owner : " << trajectoryElement->GetOwner() << std::endl; + std::cerr << "================================" << std::endl << std::endl; + } + } + + return 1; +} + int ReceiveString(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) { @@ -478,4 +539,35 @@ int ReceiveQuaternionTrackingData(igtl::ClientSocket::Pointer& socket, igtl::Mes return 0; } +int ReceiveCapability(igtl::Socket * socket, igtl::MessageHeader * header) +{ + + std::cerr << "Receiving CAPABILITY data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::CapabilityMessage::Pointer capabilMsg; + capabilMsg = igtl::CapabilityMessage::New(); + capabilMsg->SetMessageHeader(header); + capabilMsg->AllocatePack(); + + // Receive transform data from the socket + socket->Receive(capabilMsg->GetPackBodyPointer(), capabilMsg->GetPackBodySize()); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = capabilMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nTypes = capabilMsg->GetNumberOfTypes(); + for (int i = 0; i < nTypes; i ++) + { + std::cerr << "Typename #" << i << ": " << capabilMsg->GetType(i) << std::endl; + } + } + + return 1; + +} + #endif //OpenIGTLink_PROTOCOL_VERSION >= 2 diff --git a/Examples/Receiver/ReceiveServer.cxx b/Examples/Receiver/ReceiveServer.cxx index 16ee5ea8..13daf32d 100644 --- a/Examples/Receiver/ReceiveServer.cxx +++ b/Examples/Receiver/ReceiveServer.cxx @@ -30,8 +30,10 @@ #if OpenIGTLink_PROTOCOL_VERSION >= 2 #include "igtlPointMessage.h" +#include "igtlTrajectoryMessage.h" #include "igtlStringMessage.h" #include "igtlBindMessage.h" +#include "igtlCapabilityMessage.h" #endif //OpenIGTLink_PROTOCOL_VERSION >= 2 @@ -42,8 +44,10 @@ int ReceiveStatus(igtl::Socket * socket, igtl::MessageHeader * header); #if OpenIGTLink_PROTOCOL_VERSION >= 2 int ReceivePoint(igtl::Socket * socket, igtl::MessageHeader * header); +int ReceiveTrajectory(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); int ReceiveString(igtl::Socket * socket, igtl::MessageHeader * header); int ReceiveBind(igtl::Socket * socket, igtl::MessageHeader * header); +int ReceiveCapability(igtl::Socket * socket, igtl::MessageHeader * header); #endif //OpenIGTLink_PROTOCOL_VERSION >= 2 int main(int argc, char* argv[]) @@ -145,6 +149,10 @@ int main(int argc, char* argv[]) { ReceivePoint(socket, headerMsg); } + else if (strcmp(headerMsg->GetDeviceType(), "TRAJ") == 0) + { + ReceiveTrajectory(socket, headerMsg); + } else if (strcmp(headerMsg->GetDeviceType(), "STRING") == 0) { ReceiveString(socket, headerMsg); @@ -153,6 +161,10 @@ int main(int argc, char* argv[]) { ReceiveBind(socket, headerMsg); } + else if (strcmp(headerMsg->GetDeviceType(), "CAPABILITY") == 0) + { + ReceiveCapability(socket, headerMsg); + } #endif //OpenIGTLink_PROTOCOL_VERSION >= 2 else { @@ -371,6 +383,55 @@ int ReceivePoint(igtl::Socket * socket, igtl::MessageHeader * header) return 1; } +int ReceiveTrajectory(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving TRAJECTORY data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::TrajectoryMessage::Pointer trajectoryMsg; + trajectoryMsg = igtl::TrajectoryMessage::New(); + trajectoryMsg->SetMessageHeader(header); + trajectoryMsg->AllocatePack(); + + // Receive transform data from the socket + socket->Receive(trajectoryMsg->GetPackBodyPointer(), trajectoryMsg->GetPackBodySize()); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = trajectoryMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = trajectoryMsg->GetNumberOfTrajectoryElement(); + for (int i = 0; i < nElements; i ++) + { + igtl::TrajectoryElement::Pointer trajectoryElement; + trajectoryMsg->GetTrajectoryElement(i, trajectoryElement); + + igtlUint8 rgba[4]; + trajectoryElement->GetRGBA(rgba); + + igtlFloat32 entry[3]; + igtlFloat32 target[3]; + trajectoryElement->GetEntryPosition(entry); + trajectoryElement->GetTargetPosition(target); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << trajectoryElement->GetName() << std::endl; + std::cerr << " GroupName : " << trajectoryElement->GetGroupName() << std::endl; + std::cerr << " RGBA : ( " << (int)rgba[0] << ", " << (int)rgba[1] << ", " << (int)rgba[2] << ", " << (int)rgba[3] << " )" << std::endl; + std::cerr << " Entry Pt : ( " << std::fixed << entry[0] << ", " << entry[1] << ", " << entry[2] << " )" << std::endl; + std::cerr << " Target Pt : ( " << std::fixed << target[0] << ", " << target[1] << ", " << target[2] << " )" << std::endl; + std::cerr << " Radius : " << std::fixed << trajectoryElement->GetRadius() << std::endl; + std::cerr << " Owner : " << trajectoryElement->GetOwner() << std::endl; + std::cerr << "================================" << std::endl << std::endl; + } + } + + return 1; +} + int ReceiveString(igtl::Socket * socket, igtl::MessageHeader * header) { @@ -453,4 +514,37 @@ int ReceiveBind(igtl::Socket * socket, igtl::MessageHeader * header) return 1; } + +int ReceiveCapability(igtl::Socket * socket, igtl::MessageHeader * header) +{ + + std::cerr << "Receiving CAPABILITY data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::CapabilityMessage::Pointer capabilMsg; + capabilMsg = igtl::CapabilityMessage::New(); + capabilMsg->SetMessageHeader(header); + capabilMsg->AllocatePack(); + + // Receive transform data from the socket + socket->Receive(capabilMsg->GetPackBodyPointer(), capabilMsg->GetPackBodySize()); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = capabilMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nTypes = capabilMsg->GetNumberOfTypes(); + for (int i = 0; i < nTypes; i ++) + { + std::cerr << "Typename #" << i << ": " << capabilMsg->GetType(i) << std::endl; + } + } + + return 1; + +} + + #endif //OpenIGTLink_PROTOCOL_VERSION >= 2 diff --git a/Examples/SessionManager/CMakeLists.txt b/Examples/SessionManager/CMakeLists.txt new file mode 100644 index 00000000..85c60ed9 --- /dev/null +++ b/Examples/SessionManager/CMakeLists.txt @@ -0,0 +1,16 @@ +PROJECT(SessionManager) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(SessionManagerServer SessionManagerServer.cxx) +TARGET_LINK_LIBRARIES(SessionManagerServer OpenIGTLink) + +#ADD_EXECUTABLE(SessionManagerClient SessionManagerClient.cxx) +#TARGET_LINK_LIBRARIES(SessionManagerClient OpenIGTLink) diff --git a/Examples/SessionManager/SessionManagerServer.cxx b/Examples/SessionManager/SessionManagerServer.cxx new file mode 100644 index 00000000..bec75e81 --- /dev/null +++ b/Examples/SessionManager/SessionManagerServer.cxx @@ -0,0 +1,193 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Data Receiving Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlMessageHandler.h" +#include "igtlMessageHandlerMacro.h" +#include "igtlSessionManager.h" +#include "igtlTransformMessage.h" +#include "igtlPositionMessage.h" +#include "igtlImageMessage.h" + + + +//------------------------------------------------------------ +// Define a structure type to share data between message +// handler classes and main() function. +// It can be any types e.g. C++ class, array, etc. +// In this example, the shared structure is only used for +// passing the message type and the device name from the +// handler to main() function. + +typedef struct { + std::string messagetype; + std::string devicename; +} MyData; + + +//------------------------------------------------------------ +// Define message handler classes for TransformMessage, +// PositionMessage and ImageMessage. +// igtlMessageHandlerClassMacro() defines a child class of +// igtl::MessageHandler to handle OpenIGTLink messages for +// the message type specified as the first argument. The +// second argument will be used for the name of this +// message handler class, while the third argument specifies +// a type of data that will be shared with the message functions +// of this handler class. + +igtlMessageHandlerClassMacro(igtl::TransformMessage, TransformHandler, MyData); +igtlMessageHandlerClassMacro(igtl::PositionMessage, PositionHandler, MyData); +igtlMessageHandlerClassMacro(igtl::ImageMessage, ImageHandler, MyData); + + +//------------------------------------------------------------ +// You need to describe how the received message is processed +// in Process() function of the message handler class. +// When Process() is called, pointers to the received message +// and the shared data are passed as the arguments. + +// -- Transform message +int TransformHandler::Process(igtl::TransformMessage * transMsg, MyData* data) +{ + // Retrive the transform data + igtl::Matrix4x4 matrix; + transMsg->GetMatrix(matrix); + igtl::PrintMatrix(matrix); + + data->messagetype = transMsg->GetDeviceType(); + data->devicename = transMsg->GetDeviceName(); + + return 1; +} + +// -- Position message +int PositionHandler::Process(igtl::PositionMessage * positionMsg, MyData* data) +{ + // Retrive the transform data + float position[3]; + float quaternion[4]; + + positionMsg->GetPosition(position); + positionMsg->GetQuaternion(quaternion); + + std::cerr << "position = (" << position[0] << ", " << position[1] << ", " << position[2] << ")" << std::endl; + std::cerr << "quaternion = (" << quaternion[0] << ", " << quaternion[1] << ", " + << quaternion[2] << ", " << quaternion[3] << ")" << std::endl << std::endl; + + data->messagetype = positionMsg->GetDeviceType(); + data->devicename = positionMsg->GetDeviceName(); + + return 1; +} + +// -- Image message +int ImageHandler::Process(igtl::ImageMessage * imgMsg, MyData *data) +{ + // Retrive the image data + int size[3]; // image dimension + float spacing[3]; // spacing (mm/pixel) + int svsize[3]; // sub-volume size + int svoffset[3]; // sub-volume offset + int scalarType; // scalar type + + scalarType = imgMsg->GetScalarType(); + imgMsg->GetDimensions(size); + imgMsg->GetSpacing(spacing); + imgMsg->GetSubVolume(svsize, svoffset); + + std::cerr << "Device Name : " << imgMsg->GetDeviceName() << std::endl; + std::cerr << "Scalar Type : " << scalarType << std::endl; + std::cerr << "Dimensions : (" + << size[0] << ", " << size[1] << ", " << size[2] << ")" << std::endl; + std::cerr << "Spacing : (" + << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << ")" << std::endl; + std::cerr << "Sub-Volume dimensions : (" + << svsize[0] << ", " << svsize[1] << ", " << svsize[2] << ")" << std::endl; + std::cerr << "Sub-Volume offset : (" + << svoffset[0] << ", " << svoffset[1] << ", " << svoffset[2] << ")" << std::endl; + + data->messagetype = imgMsg->GetDeviceType(); + data->devicename = imgMsg->GetDeviceName(); + + return 1; +} + + +int main(int argc, char* argv[]) +{ + + //------------------------------------------------------------ + // Parse Arguments + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + //------------------------------------------------------------ + // Create a session manager + igtl::SessionManager::Pointer sm; + sm = igtl::SessionManager::New(); + sm->SetMode(igtl::SessionManager::MODE_SERVER); + sm->SetPort(port); + + //------------------------------------------------------------ + // Create message handlers + TransformHandler::Pointer tmh = TransformHandler::New(); + PositionHandler::Pointer pmh = PositionHandler::New(); + ImageHandler::Pointer imh = ImageHandler::New(); + + MyData mydata; + tmh->SetData(&mydata); + pmh->SetData(&mydata); + imh->SetData(&mydata); + + //------------------------------------------------------------ + // Register the message handlers to the session manager + sm->AddMessageHandler(tmh); + sm->AddMessageHandler(pmh); + sm->AddMessageHandler(imh); + + //------------------------------------------------------------ + // Start session + if (sm->Connect()) + { + while (1) + { + int r = sm->ProcessMessage(); + if (r == 0) // Disconnected + { + break; + } + std::cerr << "Message Type: " << tmh->GetData()->messagetype << std::endl; + std::cerr << "Device Name: " << tmh->GetData()->devicename << std::endl; + } + // Stop session + sm->Disconnect(); + } + +} + + + diff --git a/Examples/String/CMakeLists.txt b/Examples/String/CMakeLists.txt index 72cee250..14b1562b 100644 --- a/Examples/String/CMakeLists.txt +++ b/Examples/String/CMakeLists.txt @@ -15,5 +15,8 @@ TARGET_LINK_LIBRARIES(StringClient OpenIGTLink) ADD_EXECUTABLE(StringServer StringServer.cxx) TARGET_LINK_LIBRARIES(StringServer OpenIGTLink) +ADD_EXECUTABLE(StringEchoServer StringEchoServer.cxx) +TARGET_LINK_LIBRARIES(StringEchoServer OpenIGTLink) + diff --git a/Examples/String/StringClient.cxx b/Examples/String/StringClient.cxx index b8fb0285..1829ccf4 100644 --- a/Examples/String/StringClient.cxx +++ b/Examples/String/StringClient.cxx @@ -43,7 +43,7 @@ int main(int argc, char* argv[]) std::cerr << "Usage: " << argv[0] << " " << std::endl; std::cerr << " : IP or host name" << std::endl; std::cerr << " : Port # (18944 in Slicer default)" << std::endl; - std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + std::cerr << " : Frequency (fps) to send string" << std::endl; exit(0); } diff --git a/Examples/String/StringEchoServer.cxx b/Examples/String/StringEchoServer.cxx new file mode 100644 index 00000000..5988a9ac --- /dev/null +++ b/Examples/String/StringEchoServer.cxx @@ -0,0 +1,95 @@ +/*========================================================================= + + Program: Open IGT Link -- Example for String Echo Server Program + Module: $RCSfile: $ + Language: C++ + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlStringMessage.h" +#include "igtlServerSocket.h" + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + igtl::MessageHeader::Pointer hdrMsg = igtl::MessageHeader::New(); + + while (socket.IsNotNull() && socket->GetConnected()) + { + hdrMsg->InitPack(); + int r = socket->Receive(hdrMsg->GetPackPointer(), hdrMsg->GetPackSize()); + + // check message + if (r == 0) + { + socket->CloseSocket(); + continue; + } + if (r != hdrMsg->GetPackSize()) + continue; + + // get data + hdrMsg->Unpack(); + igtl::StringMessage::Pointer strMsg(igtl::StringMessage::New()); + strMsg->SetMessageHeader(hdrMsg); + strMsg->AllocatePack(); + socket->Receive(strMsg->GetPackBodyPointer(), strMsg->GetPackBodySize()); + int c = strMsg->Unpack(); + + // echo message back + std::cout << "Echoing: " << strMsg->GetString() << std::endl; + strMsg->SetDeviceName("StringEchoServer"); + strMsg->Pack(); + socket->Send(strMsg->GetPackPointer(), strMsg->GetPackSize()); + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + diff --git a/Examples/String/StringServer.cxx b/Examples/String/StringServer.cxx index fe073009..b394270d 100644 --- a/Examples/String/StringServer.cxx +++ b/Examples/String/StringServer.cxx @@ -42,7 +42,7 @@ int main(int argc, char* argv[]) // If not correct, print usage std::cerr << "Usage: " << argv[0] << " " << std::endl; std::cerr << " : Port # (18944 in Slicer default)" << std::endl; - std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + std::cerr << " : Frequency (fps) to send string" << std::endl; exit(0); } diff --git a/Examples/Trajectory/CMakeLists.txt b/Examples/Trajectory/CMakeLists.txt new file mode 100644 index 00000000..a892e3d2 --- /dev/null +++ b/Examples/Trajectory/CMakeLists.txt @@ -0,0 +1,18 @@ +PROJECT(Trajectory) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(TrajectoryClient TrajectoryClient.cxx) +TARGET_LINK_LIBRARIES(TrajectoryClient OpenIGTLink) + +ADD_EXECUTABLE(TrajectoryServer TrajectoryServer.cxx) +TARGET_LINK_LIBRARIES(TrajectoryServer OpenIGTLink) + + diff --git a/Examples/Trajectory/TrajectoryClient.cxx b/Examples/Trajectory/TrajectoryClient.cxx new file mode 100644 index 00000000..12ec2274 --- /dev/null +++ b/Examples/Trajectory/TrajectoryClient.cxx @@ -0,0 +1,113 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Trajectory message + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlTrajectoryMessage.h" +#include "igtlClientSocket.h" + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Transform Message Class + + igtl::TrajectoryMessage::Pointer trajectoryMsg; + trajectoryMsg = igtl::TrajectoryMessage::New(); + trajectoryMsg->SetDeviceName("TrajectorySender"); + + //--------------------------- + // Create 1st trajectory + igtl::TrajectoryElement::Pointer trajectory0; + trajectory0 = igtl::TrajectoryElement::New(); + trajectory0->SetName("TRAJECTORY_0"); + trajectory0->SetGroupName("GROUP_0"); + trajectory0->SetRGBA(0xFF, 0x00, 0x00, 0xFF); + trajectory0->SetEntryPosition(10.0, 20.0, 30.0); + trajectory0->SetTargetPosition(20.0, 20.0, 40.0); + trajectory0->SetRadius(15.0); + trajectory0->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 2nd trajectory + igtl::TrajectoryElement::Pointer trajectory1; + trajectory1 = igtl::TrajectoryElement::New(); + trajectory1->SetName("TRAJECTORY_1"); + trajectory1->SetGroupName("GROUP_0"); + trajectory1->SetRGBA(0x00, 0xFF, 0x00, 0xFF); + trajectory1->SetEntryPosition(40.0, 50.0, 60.0); + trajectory1->SetTargetPosition(20.0, 30.0, 10.0); + trajectory1->SetRadius(45.0); + trajectory1->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 3rd trajectory + igtl::TrajectoryElement::Pointer trajectory2; + trajectory2 = igtl::TrajectoryElement::New(); + trajectory2->SetName("TRAJECTORY_2"); + trajectory2->SetGroupName("GROUP_0"); + trajectory2->SetRGBA(0x00, 0x00, 0xFF, 0xFF); + trajectory2->SetEntryPosition(70.0, 80.0, 90.0); + trajectory1->SetTargetPosition(10.0, 40.0, 20.0); + trajectory2->SetRadius(75.0); + trajectory2->SetOwner("IMAGE_0"); + + //--------------------------- + // Pack into the trajectory message + trajectoryMsg->AddTrajectoryElement(trajectory0); + trajectoryMsg->AddTrajectoryElement(trajectory1); + trajectoryMsg->AddTrajectoryElement(trajectory2); + trajectoryMsg->Pack(); + + //------------------------------------------------------------ + // Send + socket->Send(trajectoryMsg->GetPackPointer(), trajectoryMsg->GetPackSize()); + + + //------------------------------------------------------------ + // Close the socket + socket->CloseSocket(); + +} + diff --git a/Examples/Trajectory/TrajectoryServer.cxx b/Examples/Trajectory/TrajectoryServer.cxx new file mode 100644 index 00000000..e4260c59 --- /dev/null +++ b/Examples/Trajectory/TrajectoryServer.cxx @@ -0,0 +1,120 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Trajectory message + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlTrajectoryMessage.h" +#include "igtlServerSocket.h" + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + + //--------------------------- + // Create a trajectory message + igtl::TrajectoryMessage::Pointer trajectoryMsg; + trajectoryMsg = igtl::TrajectoryMessage::New(); + trajectoryMsg->SetDeviceName("TrajectorySender"); + + //--------------------------- + // Create 1st trajectory + igtl::TrajectoryElement::Pointer trajectory0; + trajectory0 = igtl::TrajectoryElement::New(); + trajectory0->SetName("TRAJECTORY_0"); + trajectory0->SetGroupName("GROUP_0"); + trajectory0->SetRGBA(0xFF, 0x00, 0x00, 0xFF); + trajectory0->SetEntryPosition(10.0, 20.0, 30.0); + trajectory0->SetTargetPosition(20.0, 20.0, 40.0); + trajectory0->SetRadius(15.0); + trajectory0->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 2nd trajectory + igtl::TrajectoryElement::Pointer trajectory1; + trajectory1 = igtl::TrajectoryElement::New(); + trajectory1->SetName("TRAJECTORY_1"); + trajectory1->SetGroupName("GROUP_0"); + trajectory1->SetRGBA(0x00, 0xFF, 0x00, 0xFF); + trajectory1->SetEntryPosition(40.0, 50.0, 60.0); + trajectory1->SetTargetPosition(20.0, 30.0, 10.0); + trajectory1->SetRadius(45.0); + trajectory1->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 3rd trajectory + igtl::TrajectoryElement::Pointer trajectory2; + trajectory2 = igtl::TrajectoryElement::New(); + trajectory2->SetName("TRAJECTORY_2"); + trajectory2->SetGroupName("GROUP_0"); + trajectory2->SetRGBA(0x00, 0x00, 0xFF, 0xFF); + trajectory2->SetEntryPosition(70.0, 80.0, 90.0); + trajectory2->SetTargetPosition(10.0, 40.0, 20.0); + trajectory2->SetRadius(75.0); + trajectory2->SetOwner("IMAGE_0"); + + //--------------------------- + // Pack into the trajectory message + trajectoryMsg->AddTrajectoryElement(trajectory0); + trajectoryMsg->AddTrajectoryElement(trajectory1); + trajectoryMsg->AddTrajectoryElement(trajectory2); + trajectoryMsg->Pack(); + + //--------------------------- + // Send + socket->Send(trajectoryMsg->GetPackPointer(), trajectoryMsg->GetPackSize()); + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + } + + socket->CloseSocket(); + +} + + diff --git a/README b/README.md similarity index 53% rename from README rename to README.md index 030fbe2e..3b76337c 100644 --- a/README +++ b/README.md @@ -1,10 +1,13 @@ +The OpenIGTLink Library +======================= + This project provides an implementation of the OpenIGTLink protocol defined in - http://openigtlink.org/ + http://openigtlink.org/ The code is distributed as open source under the new BSD liccense: - http://www.opensource.org/licenses/bsd-license.php + http://www.opensource.org/licenses/bsd-license.php diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e8545aea..df08e6ba 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -51,6 +51,7 @@ SET(OpenIGTLink_SOURCES igtlObjectFactoryBase.cxx igtlPositionMessage.cxx igtlServerSocket.cxx + igtlSessionManager.cxx igtlSimpleFastMutexLock.cxx igtlSocket.cxx igtlStatusMessage.cxx @@ -66,6 +67,9 @@ SET(OpenIGTLink_INCLUDE_FILES igtlutil/igtl_types.h igtlutil/igtl_util.h igtlutil/igtl_capability.h + igtlutil/igtl_win32header.h + igtlMessageHandler.h + igtlMessageHandlerMacro.h igtlClientSocket.h igtlConditionVariable.h igtlCreateObjectFunction.h @@ -85,6 +89,7 @@ SET(OpenIGTLink_INCLUDE_FILES igtlObjectFactoryBase.h igtlPositionMessage.h igtlServerSocket.h + igtlSessionManager.h igtlSimpleFastMutexLock.h igtlSmartPointer.h igtlSocket.h @@ -115,6 +120,7 @@ if (${OpenIGTLink_PROTOCOL_VERSION} STREQUAL "2") igtlutil/igtl_qtrans.c igtlutil/igtl_polydata.c igtlColorTableMessage.cxx + igtlCapabilityMessage.cxx igtlImageMetaMessage.cxx igtlLabelMetaMessage.cxx igtlPointMessage.cxx @@ -145,6 +151,7 @@ if (${OpenIGTLink_PROTOCOL_VERSION} STREQUAL "2") igtlutil/igtl_qtrans.h igtlutil/igtl_polydata.h igtlColorTableMessage.h + igtlCapabilityMessage.h igtlImageMetaMessage.h igtlLabelMetaMessage.h igtlPointMessage.h diff --git a/Source/igtlCapabilityMessage.cxx b/Source/igtlCapabilityMessage.cxx new file mode 100755 index 00000000..2ae24ca7 --- /dev/null +++ b/Source/igtlCapabilityMessage.cxx @@ -0,0 +1,171 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Module: + Language: C++ + Date: + Version: + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlCapabilityMessage.h" + +#include + +#include +#include +#include + +#include +#include + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include + +namespace igtl { + +CapabilityMessage::CapabilityMessage(): + MessageBase() +{ + this->m_DefaultBodyType = "CAPABILITY"; + this->m_TypeNames.clear(); +} + + +CapabilityMessage::~CapabilityMessage() +{ + this->m_TypeNames.clear(); +} + + +//void CapabilityMessage::SetTypes(int ntypes, const char names[][IGTL_HEADER_TYPE_SIZE]) +//{ +// this->m_TypeNames.clear(); +// +// for(int i = 0; i < ntypes; i++) +// { +// std::string buf; +// if (strnlen(names[i], IGTL_HEADER_TYPE_SIZE) < IGTL_HEADER_TYPE_SIZE) +// { +// buf.append(names[i]); +// } +// else +// { +// buf.append(names[i], IGTL_HEADER_TYPE_SIZE); +// } +// this->m_TypeNames.push_back(buf); +// } +//} + + +void CapabilityMessage::SetTypes(std::vector types) +{ + this->m_TypeNames.clear(); + this->m_TypeNames = types; +} + + +int CapabilityMessage::SetType(int id, const char* type) +{ + if (id < (int)this->m_TypeNames.size() && strlen(type) < IGTL_HEADER_TYPE_SIZE) + { + this->m_TypeNames[id] = type; + return 1; + } + else + { + return 0; + } +} + + +const char* CapabilityMessage::GetType(int id) +{ + if (id < (int)this->m_TypeNames.size()) + { + return this->m_TypeNames[id].c_str(); + } + else + { + return ""; + } +} + + +int CapabilityMessage::GetBodyPackSize() +{ + return (sizeof(char) * IGTL_HEADER_TYPE_SIZE * this->m_TypeNames.size()); +} + + +int CapabilityMessage::PackBody() +{ + AllocatePack(); + + if (this->m_TypeNames.size() == 0) + { + return 0; + } + + igtl_capability_info info; + int nTypes = this->m_TypeNames.size(); + + igtl_capability_init_info(&info); + info.ntypes = nTypes; + igtl_capability_alloc_info(&info, nTypes); + + for(int i = 0; i < nTypes; i++ ) + { + memcpy(info.typenames[i], this->m_TypeNames[i].c_str(), IGTL_HEADER_TYPE_SIZE); + } + + igtl_capability_pack(&info, this->m_Body); + + return 1; +} + + +int CapabilityMessage::UnpackBody() +{ + + igtl_capability_info info; + + igtl_capability_init_info(&info); + igtl_capability_unpack(this->m_Body, &info, this->GetPackBodySize()); + + int ntypes = info.ntypes; + + if(ntypes == 0) + { + return 0; + } + + this->m_TypeNames.clear(); + for(int i = 0; i < ntypes; i++) + { + std::string buf; + if (igtl::Strnlen((const char*)info.typenames[i], IGTL_HEADER_TYPE_SIZE) < IGTL_HEADER_TYPE_SIZE) + { + buf.append((const char*)info.typenames[i]); + } + else + { + buf.append((const char*)info.typenames[i], IGTL_HEADER_TYPE_SIZE); + } + this->m_TypeNames.push_back(buf); + } + + + return 1; +} + + +} // namespace igtl diff --git a/Source/igtlCapabilityMessage.h b/Source/igtlCapabilityMessage.h new file mode 100755 index 00000000..e836c359 --- /dev/null +++ b/Source/igtlCapabilityMessage.h @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlCapabilityMessage_h +#define __igtlCapabilityMessage_h + +#include +#include +#include +#include + +#include +#include + +namespace igtl +{ + +class IGTLCommon_EXPORT GetCapabilityMessage: public MessageBase +{ +public: + typedef GetCapabilityMessage Self; + typedef MessageBase Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + igtlTypeMacro(igtl::GetCapabilityMessage, igtl::MessageBase); + igtlNewMacro(igtl::GetCapabilityMessage); + +protected: + GetCapabilityMessage() : MessageBase() { this->m_DefaultBodyType = "GET_CAPABIL"; }; + ~GetCapabilityMessage() {}; +protected: + virtual int GetBodyPackSize() { return 0; }; + virtual int PackBody() { AllocatePack(); return 1; }; + virtual int UnpackBody() { return 1; }; +}; + + +class IGTLCommon_EXPORT CapabilityMessage: public MessageBase +{ + +public: + + typedef CapabilityMessage Self; + typedef MessageBase Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + igtlTypeMacro(igtl::CapabilityMessage, igtl::MessageBase); + igtlNewMacro(igtl::CapabilityMessage); + +public: + + //void SetTypes(int ntypes, const char names[][IGTL_HEADER_TYPE_SIZE]); + void SetTypes(std::vector types); + int SetType(int id, const char* name); + const char* GetType(int id); + + void SetNumberOfTypes(int n) { m_TypeNames.resize(n); } + int GetNumberOfTypes() { return m_TypeNames.size(); } + //char** GetTypeNames() { return m_TypeNames; } + std::vector GetTypes() { return m_TypeNames; } + +protected: + CapabilityMessage(); + ~CapabilityMessage(); + +protected: + + virtual int GetBodyPackSize(); + virtual int PackBody(); + virtual int UnpackBody(); + + std::vector m_TypeNames; + +}; + + +} // namespace igtl + +#endif // __igtlCapabilityMessage_h diff --git a/Source/igtlImageMessage.cxx b/Source/igtlImageMessage.cxx index ba0d4e60..b0231c31 100644 --- a/Source/igtlImageMessage.cxx +++ b/Source/igtlImageMessage.cxx @@ -30,19 +30,14 @@ ImageMessage::ImageMessage(): subDimensions[i] = 0; subOffset[i] = 0; } - for (int i = 0; i < 3; i ++) + for (int i = 0; i < 4; i ++) { for (int j = 0; j < 4; j ++) { - matrix[i][j] = 0.0; + matrix[i][j] = (i == j ? 1.0 : 0.0); } } - matrix[3][0] = 0.0; - matrix[3][1] = 0.0; - matrix[3][2] = 0.0; - matrix[3][3] = 1.0; - endian = ENDIAN_BIG; coordinate = COORDINATE_RAS; scalarType = TYPE_UINT8; diff --git a/Source/igtlImageMessage.h b/Source/igtlImageMessage.h index c4489311..31b11bb3 100644 --- a/Source/igtlImageMessage.h +++ b/Source/igtlImageMessage.h @@ -24,27 +24,22 @@ namespace igtl { // A class for the GEt_IMAGE message type. -class IGTLCommon_EXPORT GetImageMessage: public MessageBase +class IGTLCommon_EXPORT GetImageMessage: public HeaderOnlyMessageBase { public: typedef GetImageMessage Self; - typedef MessageBase Superclass; + typedef HeaderOnlyMessageBase Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; - igtlTypeMacro(igtl::GetImageMessage, igtl::MessageBase); + igtlTypeMacro(igtl::GetImageMessage, igtl::HeaderOnlyMessageBase); igtlNewMacro(igtl::GetImageMessage); protected: - GetImageMessage() : MessageBase() { this->m_DefaultBodyType = "GET_IMAGE"; }; + GetImageMessage() : HeaderOnlyMessageBase() { this->m_DefaultBodyType = "GET_IMAGE"; }; ~GetImageMessage() {}; -protected: - - virtual int GetBodyPackSize() { return 0; }; - virtual int PackBody() { AllocatePack(); return 1; }; - virtual int UnpackBody() { return 1; }; }; @@ -236,12 +231,19 @@ class IGTLCommon_EXPORT ImageMessage: public MessageBase /// Gets the size (length) of the byte array for the image data. /// The size is defined by dimensions[0]*dimensions[1]*dimensions[2]*scalarSize*numComponents. - // TODO: Should returned value be 64-bit integer? + /// TODO: Should returned value be 64-bit integer? int GetImageSize() { return dimensions[0]*dimensions[1]*dimensions[2]*GetScalarSize()*numComponents; }; + /// Returns coordinate system (COORDINATE_RAS or COORDINATE_LPS) + int GetCoordinateSystem() { return coordinate;}; + + /// Sets coordinate system (COORDINATE_RAS or COORDINATE_LPS) + void SetCoordinateSystem(int c) {coordinate = c;}; + + /// Gets the size (length) of the byte array for the subvolume image data. /// The size is defined by subDimensions[0]*subDimensions[1]*subDimensions[2]* /// scalarSize*numComponents. @@ -281,6 +283,7 @@ class IGTLCommon_EXPORT ImageMessage: public MessageBase int subOffset[3]; /// A matrix representing the origin and the orientation of the image. + /// The matrix is set to identity by default Matrix4x4 matrix; /// A variable for the Endian of the scalar values in the image. diff --git a/Source/igtlImageMessage2.cxx b/Source/igtlImageMessage2.cxx index 4577e8df..d5fa8671 100644 --- a/Source/igtlImageMessage2.cxx +++ b/Source/igtlImageMessage2.cxx @@ -32,19 +32,14 @@ ImageMessage2::ImageMessage2(): subDimensions[i] = 0; subOffset[i] = 0; } - for (int i = 0; i < 3; i ++) + for (int i = 0; i < 4; i ++) { for (int j = 0; j < 4; j ++) { - matrix[i][j] = 0.0; + matrix[i][j] = (i == j ? 1.0 : 0.0); } } - matrix[3][0] = 0.0; - matrix[3][1] = 0.0; - matrix[3][2] = 0.0; - matrix[3][3] = 1.0; - endian = ENDIAN_BIG; coordinate = COORDINATE_RAS; scalarType = TYPE_UINT8; @@ -493,7 +488,7 @@ int ImageMessage2::GetPackFragmentSize(int id) return GetSubVolumeImageSize(); } - return NULL; + return 0; } #endif // FRAGMENTED_PACK diff --git a/Source/igtlImageMessage2.h b/Source/igtlImageMessage2.h index 18e2bde9..d400e256 100644 --- a/Source/igtlImageMessage2.h +++ b/Source/igtlImageMessage2.h @@ -92,8 +92,8 @@ class IGTLCommon_EXPORT ImageMessage2: public MessageBase /// Coordinate sysmtem. Either left-posterior-superior (LPS) or right-anterior-superior (RAS). enum { - COORDINATE_LPS, - COORDINATE_RAS + COORDINATE_RAS=1, + COORDINATE_LPS=2 }; /// Endian used in the bite array for the image data. @@ -258,6 +258,12 @@ class IGTLCommon_EXPORT ImageMessage2: public MessageBase return dimensions[0]*dimensions[1]*dimensions[2]*GetScalarSize()*numComponents; }; + /// Returns coordinate system (COORDINATE_RAS or COORDINATE_LPS) + int GetCoordinateSystem() { return coordinate;}; + + /// Sets coordinate system (COORDINATE_RAS or COORDINATE_LPS) + void SetCoordinateSystem(int c) {coordinate = c;}; + /// Gets the size (length) of the byte array for the subvolume image data. /// The size is defined by subDimensions[0]*subDimensions[1]*subDimensions[2]* /// scalarSize*numComponents. @@ -334,6 +340,7 @@ class IGTLCommon_EXPORT ImageMessage2: public MessageBase int subOffset[3]; /// A matrix representing the origin and the orientation of the image. + /// The matrix is set to identity by default Matrix4x4 matrix; /// A variable for the Endian of the scalar values in the image. diff --git a/Source/igtlImageMetaMessage.cxx b/Source/igtlImageMetaMessage.cxx index 514b01fe..b811f624 100644 --- a/Source/igtlImageMetaMessage.cxx +++ b/Source/igtlImageMetaMessage.cxx @@ -257,7 +257,14 @@ int ImageMetaMessage::PackBody() igtl::TimeStamp::Pointer ts; (*iter)->GetTimeStamp(ts); - element->timestamp = ts->GetTimeStampUint64(); + if (ts.IsNotNull()) + { + element->timestamp = ts->GetTimeStampUint64(); + } + else + { + element->timestamp = 0; + } igtlUint16 size[3]; (*iter)->GetSize(size); element->size[0] = size[0]; diff --git a/Source/igtlLabelMetaMessage.cxx b/Source/igtlLabelMetaMessage.cxx index bff59255..0ffbd236 100644 --- a/Source/igtlLabelMetaMessage.cxx +++ b/Source/igtlLabelMetaMessage.cxx @@ -285,7 +285,7 @@ int LabelMetaMessage::UnpackBody() elemClass->SetSize(element->size); strbuf[IGTL_LBMETA_LEN_OWNER] = '\n'; - strncpy(strbuf, (char*)element->device_name, IGTL_LBMETA_LEN_OWNER); + strncpy(strbuf, (char*)element->owner, IGTL_LBMETA_LEN_OWNER); elemClass->SetOwner(strbuf); this->m_LabelMetaList.push_back(elemClass); diff --git a/Source/igtlMessageBase.h b/Source/igtlMessageBase.h index e4584591..66d238cc 100644 --- a/Source/igtlMessageBase.h +++ b/Source/igtlMessageBase.h @@ -26,7 +26,6 @@ #include - namespace igtl { @@ -218,6 +217,51 @@ class IGTLCommon_EXPORT MessageBase: public Object }; +/// A class for header-only message types, which are used for quearying. +class IGTLCommon_EXPORT HeaderOnlyMessageBase: public MessageBase +{ +public: + typedef HeaderOnlyMessageBase Self; + typedef MessageBase Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + igtlTypeMacro(igtl::HeaderOnlyMessageBase, igtl::MessageBase); + igtlNewMacro(igtl::HeaderOnlyMessageBase); + +protected: + HeaderOnlyMessageBase() { this->m_DefaultBodyType = ""; }; + ~HeaderOnlyMessageBase() {}; + +protected: + + virtual int GetBodyPackSize() { return 0; }; + virtual int PackBody() { AllocatePack(); return 1; }; + virtual int UnpackBody() { return 1; }; + +}; + + +/// A macro to help defining a class for query message types +/// that do not have message bodies. +// TODO: Need test. +#define igtlCreateDefaultQueryMessageClass(name, msgtype) \ +class IGTLCommon_EXPORT name : public HeaderOnlyMessageBase\ +{ \ +public: \ + typedef name Self; \ + typedef HeaderOnlyMessageBase Superclass; \ + typedef SmartPointer Pointer; \ + typedef SmartPointer ConstPointer; \ + \ + igtlTypeMacro(igtl::name, igtl::HeaderOnlyMessageBase); \ + igtlNewMacro(igtl::name); \ + \ +protected: \ + name() : HeaderOnlyMessageBase() { this->m_DefaultBodyType = msgtype; }; \ + ~name() {}; \ +}; + } // namespace igtl #endif // _igtlMessageBase_h diff --git a/Source/igtlMessageHandler.h b/Source/igtlMessageHandler.h new file mode 100644 index 00000000..0f1c3943 --- /dev/null +++ b/Source/igtlMessageHandler.h @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: git@github.com:openigtlink/OpenIGTLink.git + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlMessageHandler_h +#define __igtlMessageHandler_h + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlSocket.h" +#include "igtlMessageBase.h" + +namespace igtl +{ + +class IGTLCommon_EXPORT MessageHandler: public Object +{ + public: + + typedef MessageHandler Self; + typedef Object Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + igtlTypeMacro(igtl::MessageHandler, igtl::Object) + igtlNewMacro(igtl::MessageHandler); + + public: + virtual const char* GetMessageType() { return ""; } + virtual int ReceiveMessage(Socket*, MessageBase*, int) { return 0; }; + + void SetMessageBuffer(MessageBase* buffer) { this->m_Buffer = buffer; } + MessageBase * GetMessageBuffer() { return this->m_Buffer; } + + protected: + MessageHandler() {} + ~MessageHandler() {} + + + + protected: + MessageBase * m_Buffer; + +}; + +} // namespace igtl + +#endif // _igtlMessageHandler_h + + + + + diff --git a/Source/igtlMessageHandlerMacro.h b/Source/igtlMessageHandlerMacro.h new file mode 100644 index 00000000..7d80500b --- /dev/null +++ b/Source/igtlMessageHandlerMacro.h @@ -0,0 +1,122 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: git@github.com:openigtlink/OpenIGTLink.git + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlMessageHandlerMacro_h +#define __igtlMessageHandlerMacro_h + +#include "igtlMessageHandler.h" + +// Description: +// The igtlMessageHandlerClassMacro() macro is to help developers to +// define message handler class. It generates a chlid class of igtl::MessageHandler. +// The developer only needs to implement ProcessMessage() after calling this macro. +// The following code shows how to define a handler that processes IMAGE message: +// +// igtlMessageHandlerClassMacro(igtl::ImageMessage, TestImageMessageHandler); +// void TestImageMessageHandler::Process(igtl::ImageMessage * message) +// { +// // do something +// } + +//#define igtlMessageHandlerClassMacro(messagetype, classname) \ +// template \ +// class classname : public MessageHandler \ +// { \ +// typedef classname Self; \ +// typedef MessageHandler Superclass; \ +// typedef SmartPointer Pointer; \ +// typedef SmartPointer ConstPointer; \ +// igtlTypeMacro(classname, MessageHandler); \ +// igtlNewMacro(classname); \ +// public: \ +// virtual void Process(messagetype*); \ +// }; + +#define igtlMessageHandlerClassMacro(messagetype, classname, datatype) \ + class classname : public ::igtl::MessageHandler \ + { \ + public: \ + typedef classname Self; \ + typedef ::igtl::MessageHandler Superclass; \ + typedef igtl::SmartPointer Pointer; \ + typedef igtl::SmartPointer ConstPointer; \ + igtlTypeMacro(classname, ::igtl::MessageHandler); \ + igtlNewMacro(classname); \ + public: \ + virtual const char* GetMessageType() \ + { \ + return this->m_Message->GetDeviceType(); \ + } \ + virtual int Process(messagetype*, datatype*); \ + int ReceiveMessage(::igtl::Socket* socket, ::igtl::MessageBase* header, int pos) \ + { \ + if (pos == 0) /* New body */ \ + { \ + this->m_Message->SetMessageHeader(header); \ + this->m_Message->AllocatePack(); \ + } \ + int s = socket->Receive((void*)((char*)this->m_Message->GetPackBodyPointer()+pos), \ + this->m_Message->GetPackBodySize()-pos); \ + if (s < 0) /* Time out */ \ + { \ + return pos; \ + } \ + if (s+pos >= this->m_Message->GetPackBodySize()) \ + { \ + int r = this->m_Message->Unpack(this->m_CheckCRC); \ + if (r) \ + { \ + Process(this->m_Message, this->m_Data); \ + } \ + else \ + { \ + return -1; \ + } \ + } \ + return s + pos; /* return current position in the body */ \ + } \ + virtual void CheckCRC(int i) \ + { \ + if (i == 0) \ + { \ + this->m_CheckCRC = 0; \ + } \ + else \ + { \ + this->m_CheckCRC = 1; \ + } \ + } \ + void SetData(datatype* p) \ + { \ + this->m_Data = p; \ + } \ + datatype* GetData() \ + { \ + return this->m_Data; \ + } \ + protected: \ + classname() \ + { \ + this->m_Message = messagetype::New(); \ + this->m_CheckCRC = 1; \ + this->m_Data = NULL; \ + } \ + ~classname() {} \ + protected: \ + int m_CheckCRC; \ + messagetype::Pointer m_Message; \ + datatype* m_Data; \ + }; + +#endif // __igtlMessageHandlerMacro_h diff --git a/Source/igtlNDArrayMessage.cxx b/Source/igtlNDArrayMessage.cxx index 5a02d1bc..e348a8fa 100644 --- a/Source/igtlNDArrayMessage.cxx +++ b/Source/igtlNDArrayMessage.cxx @@ -215,7 +215,7 @@ int NDArrayMessage::PackBody() s[i] = size[i]; } int r = igtl_ndarray_alloc_info(&info, s); - delete s; + delete [] s; if (r == 0) { diff --git a/Source/igtlOSUtil.cxx b/Source/igtlOSUtil.cxx index 17e119bf..692bf95b 100644 --- a/Source/igtlOSUtil.cxx +++ b/Source/igtlOSUtil.cxx @@ -18,8 +18,11 @@ #include #else #include + #include #endif +#include + namespace igtl { @@ -35,11 +38,32 @@ void Sleep(int milliseconds) struct timespec req; req.tv_sec = (int) milliseconds / 1000; req.tv_nsec = (milliseconds % 1000) * 1000000; - - nanosleep(&req, NULL); + + while ((nanosleep(&req, &req) == -1) && (errno == EINTR)) + { + continue; + } #endif +} + + + +// strnlen(), if not defined +#ifndef OpenIGTLink_HAVE_STRNLEN +size_t Strnlen(const char* s, size_t maxlen) +{ + + size_t i; + + for(i = 0; i < maxlen; i++) { + if(s[i] == '\0') return i; + } + return maxlen; + } +#endif + } diff --git a/Source/igtlOSUtil.h b/Source/igtlOSUtil.h index f6d1ac75..4b8f7d1b 100644 --- a/Source/igtlOSUtil.h +++ b/Source/igtlOSUtil.h @@ -15,6 +15,8 @@ #ifndef __igltOSUtil_h #define __igltOSUtil_h +#include + #include "igtlWin32Header.h" namespace igtl { @@ -24,6 +26,14 @@ namespace igtl * */ void IGTLCommon_EXPORT Sleep(int millisecond); + /** Just in case strnlen() is not defined (e.g. Mac OS X Snow Leopard) */ +#ifndef OpenIGTLink_HAVE_STRNLEN + size_t IGTLCommon_EXPORT Strnlen(const char* s, size_t maxlen); +#else + inline size_t IGTLCommon_EXPORT Strnlen(const char* s, size_t maxlen) + { return strnlen(s, maxlen); } +#endif + } #endif // __igltOSUtil_h diff --git a/Source/igtlPolyDataMessage.cxx b/Source/igtlPolyDataMessage.cxx index 1ced66fe..83214020 100644 --- a/Source/igtlPolyDataMessage.cxx +++ b/Source/igtlPolyDataMessage.cxx @@ -805,9 +805,10 @@ int PolyDataMessage::UnpackBody() // Attributes this->m_Attributes.clear(); + igtl_polydata_attribute * attr = info.attributes; for (unsigned int i = 0; i < info.header.nattributes; i ++) { - igtl_polydata_attribute * attr = info.attributes; + PolyDataAttribute::Pointer pda = PolyDataAttribute::New(); if (pda.IsNotNull()) diff --git a/Source/igtlSessionManager.cxx b/Source/igtlSessionManager.cxx new file mode 100644 index 00000000..1065153c --- /dev/null +++ b/Source/igtlSessionManager.cxx @@ -0,0 +1,309 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: git@github.com:openigtlink/OpenIGTLink.git + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include + +#include "igtlSessionManager.h" +#include "igtlMessageHandler.h" +#include "igtlClientSocket.h" +#include "igtlServerSocket.h" + +#include "igtl_header.h" + +namespace igtl +{ + + +SessionManager::SessionManager() +{ + this->m_MessageHandlerList.clear(); + this->m_Mode = MODE_SERVER; + + this->m_Header = igtl::MessageHeader::New(); + this->m_TimeStamp = igtl::TimeStamp::New(); + + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; +} + + +SessionManager::~SessionManager() +{ +} + + +int SessionManager::AddMessageHandler(MessageHandler* handler) +{ + // Check if there is any handler for the same message type + std::vector< MessageHandler* >::iterator iter; + for (iter = this->m_MessageHandlerList.begin(); iter != this->m_MessageHandlerList.end(); iter ++) + { + if (strcmp((*iter)->GetMessageType(), handler->GetMessageType()) == 0) + { + return 0; + } + } + + // If not, add the handler to the list. + this->m_MessageHandlerList.push_back(handler); + + return 1; +} + + +int SessionManager::RemoveMessageHandler(MessageHandler* handler) +{ + // Check if there is any handler for the same message type + std::vector< MessageHandler* >::iterator iter; + for (iter = this->m_MessageHandlerList.begin(); iter != this->m_MessageHandlerList.end(); iter ++) + { + if (*iter == handler) + { + this->m_MessageHandlerList.erase(iter); + return 1; + } + } + return 0; +} + + +int SessionManager::Connect() +{ + + this->m_Socket = NULL; + + if (this->m_Mode == MODE_CLIENT) + { + ClientSocket::Pointer clientSocket; + clientSocket = ClientSocket::New(); + //this->DebugOff(); + if (this->m_Hostname.length() == 0) + { + return 0; + } + //this->m_Socket->SetConnectTimeout(1000); + int r = clientSocket->ConnectToServer(this->m_Hostname.c_str(), this->m_Port); + if (r == 0) // if connected to server + { + //clientSocket->SetReceiveTimeout(0); + this->m_Socket = clientSocket; + } + } + else + { + ServerSocket::Pointer serverSocket; + serverSocket = ServerSocket::New(); + int r = serverSocket->CreateServer(this->m_Port); + if (r < 0) + { + return 0; + } + + if (serverSocket.IsNotNull()) + { + //this->ServerSocket->CreateServer(this->m_Port); + this->m_Socket = serverSocket->WaitForConnection(10000); + } + + if (this->m_Socket.IsNotNull() && this->m_Socket->GetConnected()) // if client connected + { + this->m_Socket->DebugOff(); + } + else + { + return 0; + } + } + + this->m_Socket->SetReceiveBlocking(0); // Psuedo non-blocking + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; + return 1; +} + + +int SessionManager::Disconnect() +{ + if (this->m_Socket.IsNotNull()) + { + this->m_Socket->CloseSocket(); + } + + return 0; +} + +int SessionManager::ProcessMessage() +{ + // The workflow of this function is as follows: + // + // HEADER: + // IF the message is (a) a new message: + // start reading the header; + // ELSE IF the message is a message in progress: + // if the process is reading the header: + // continue to read the header; + // ELSE: + // GOTO BODY; + // + // IF the header has not been received: + // GOTO BODY; + // ELSE + // RETURN; + // + // BODY: + // IF the process has not started reading the body: + // check the body type; + // find an appropriate handler; + // start reading the body + // ELSE: + // continue to read the body + // + + //-------------------------------------------------- + // Header + if (this->m_CurrentReadIndex == 0) + { + // Initialize receive buffer + this->m_Header->InitPack(); + + // Receive generic header from the socket + int r = this->m_Socket->Receive(this->m_Header->GetPackPointer(), this->m_Header->GetPackSize(), 0); + if (r == 0) + { + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; + return 0; // Disconnected + } + if (r != this->m_Header->GetPackSize()) + { + // Only a part of header has arrived. + if (r < 0) // timeout + { + this->m_CurrentReadIndex = 0; + } + else + { + this->m_CurrentReadIndex = r; + } + return -1; + } + // The header has been received. + this->m_CurrentReadIndex = IGTL_HEADER_SIZE; + } + else if (this->m_CurrentReadIndex < IGTL_HEADER_SIZE) + { + // Message transfer was interrupted in the header + int r = this->m_Socket->Receive((void*)((char*)this->m_Header->GetPackPointer()+this->m_CurrentReadIndex), + this->m_Header->GetPackSize()-this->m_CurrentReadIndex, 0); + if (r == 0) + { + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; + return 0; // Disconnected + } + if (r != this->m_Header->GetPackSize()-this->m_CurrentReadIndex) + { + // Only a part of header has arrived. + if (r > 0) // exclude a case of timeout + { + this->m_CurrentReadIndex += r; + } + return -1; + } + // The header has been received. + this->m_CurrentReadIndex = IGTL_HEADER_SIZE; + } + + + //-------------------------------------------------- + // Body + if (this->m_HeaderDeserialized == 0) + { + // Deserialize the header + this->m_Header->Unpack(); + + // Get time stamp + igtlUint32 sec; + igtlUint32 nanosec; + + this->m_Header->GetTimeStamp(this->m_TimeStamp); + this->m_TimeStamp->GetTimeStamp(&sec, &nanosec); + //std::cerr << "Time stamp: " + // << sec << "." << std::setw(9) << std::setfill('0') + // << nanosec << std::endl; + + // Look for a message handler that matches to the message type. + int found = 0; + std::vector< MessageHandler* >::iterator iter; + for (iter = this->m_MessageHandlerList.begin(); iter != this->m_MessageHandlerList.end(); iter ++) + { + if (strcmp(this->m_Header->GetDeviceType(), (*iter)->GetMessageType()) == 0) + { + this->m_CurrentMessageHandler = *iter; + found = 1; + break; + } + } + + // If there is no message handler, skip the message + if (!found) + { + std::cerr << "Receiving: " << this->m_Header->GetDeviceType() << std::endl; + this->m_Socket->Skip(this->m_Header->GetBodySizeToRead(), 0); + // Reset the index counter to be ready for the next message + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; + return 1; + } + + this->m_HeaderDeserialized = 1; + } + + int r = this->m_CurrentMessageHandler->ReceiveMessage(this->m_Socket, this->m_Header, + this->m_CurrentReadIndex-IGTL_HEADER_SIZE); + if (r == this->m_Header->GetBodySizeToRead()) + { + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; + } + else + { + this->m_CurrentReadIndex += IGTL_HEADER_SIZE + r; + } + + return 1; +} + + +int SessionManager::PushMessage(MessageBase* message) +{ + + if (message && this->m_Socket.IsNotNull() && this->m_Socket->GetConnected()) // if client connected + { + return this->m_Socket->Send(message->GetPackPointer(), message->GetPackSize()); + } + else + { + return 0; + } +} + + +} + + diff --git a/Source/igtlSessionManager.h b/Source/igtlSessionManager.h new file mode 100644 index 00000000..71042c09 --- /dev/null +++ b/Source/igtlSessionManager.h @@ -0,0 +1,96 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: git@github.com:openigtlink/OpenIGTLink.git + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlSessionManager_h +#define __igtlSessionManager_h + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlMessageHandler.h" + + +#include + +namespace igtl +{ + +class IGTLCommon_EXPORT SessionManager: public Object +{ + public: + + typedef SessionManager Self; + typedef Object Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + igtlTypeMacro(SessionManager, Object) + igtlNewMacro(SessionManager); + + public: + enum { + MODE_SERVER, + MODE_CLIENT + }; + + void SetHostname(const char * str) {this->m_Hostname = str; this->m_ConfigurationUpdated = true; } + const char * GetHostname() { return this->m_Hostname.c_str(); } + void SetPort(int p) { this->m_Port = p; this->m_ConfigurationUpdated = true; } + int GetPort() { return this->m_Port; } + + // Description: + // Set the role of session manager. Either MODE_SERVER or MODE_CLIENT + void SetMode(int m) {this->m_Mode = m; this->m_ConfigurationUpdated = true; } + int GetMode() {return this->m_Mode; } + + // Description: + // Register / Unregister a message handler + int AddMessageHandler(MessageHandler*); + int RemoveMessageHandler(MessageHandler*); + + // Description: + // Functions to manage the session + int Connect(); + int Disconnect(); + int ProcessMessage(); + int PushMessage(MessageBase*); + + protected: + SessionManager(); + ~SessionManager(); + + protected: + bool m_ConfigurationUpdated; + std::string m_Hostname; + int m_Port; + int m_Mode; + + // Description: + // m_CurrentReadIndex is used to save the current position of the message. + // The index becomes >0 when message transfer is interrupted and only a part + // of message has arrived. + int m_CurrentReadIndex; + int m_HeaderDeserialized; + + MessageHandler* m_CurrentMessageHandler; + + std::vector< MessageHandler* > m_MessageHandlerList; + Socket::Pointer m_Socket; + + igtl::MessageHeader::Pointer m_Header; + igtl::TimeStamp::Pointer m_TimeStamp; + +}; + +} +#endif // __igtlSessionManager_h diff --git a/Source/igtlSocket.cxx b/Source/igtlSocket.cxx index 316dbca4..b447ccc2 100644 --- a/Source/igtlSocket.cxx +++ b/Source/igtlSocket.cxx @@ -48,7 +48,7 @@ #define WSA_VERSION MAKEWORD(1,1) #define igtlCloseSocketMacro(sock) (closesocket(sock)) #else -#define igtlCloseSocketMacro(sock) (close(sock)) +#define igtlCloseSocketMacro(sock) (shutdown(sock, 2)) #endif namespace igtl @@ -312,9 +312,25 @@ int Socket::Send(const void* data, int length) #if defined(_WIN32) && !defined(__CYGWIN__) flags = 0; #else - // disabling, since not present on SUN. - // flags = MSG_NOSIGNAL; //disable signal on Unix boxes. + // On unix boxes if the client disconnects and the server attempts + // to send data through the socket then the application crashes + // due to SIGPIPE signal. Disable the signal to prevent crash. + //#ifndef __sun + // flags = MSG_NOSIGNAL; + //#else + // // Signal is not present on SUN systems, the signal has + // // to be managed at application level. + // flags = 0; + //#endif + #if defined(MSG_NOSIGNAL) // For Linux > 2.2 + flags = MSG_NOSIGNAL; + #else + #if defined(SO_NOSIGPIPE) // Mac OS X + int set = 1; + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); + #endif flags = 0; + #endif #endif int n = send(this->m_SocketDescriptor, buffer+total, length-total, flags); if(n < 0) @@ -342,14 +358,12 @@ int Socket::Receive(void* data, int length, int readFully/*=1*/) #if defined(_WIN32) && !defined(__CYGWIN__) int trys = 0; #endif + int n = recv(this->m_SocketDescriptor, buffer+total, length-total, 0); - if (n < 0 && this->m_ReceiveTimeoutFlag) // Timeout - { - return -1; - } - if(n < 1) - { + #if defined(_WIN32) && !defined(__CYGWIN__) + if(n == 0) + { // On long messages, Windows recv sometimes fails with WSAENOBUFS, but // will work if you try again. int error = WSAGetLastError(); @@ -358,10 +372,27 @@ int Socket::Receive(void* data, int length, int readFully/*=1*/) Sleep(1); continue; } -#endif // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Receive failed."); return 0; } + else if (n < 0) + { + // TODO: Need to check if this means timeout. + return -1; + } +#else + if(n == 0) // Disconnected + { + // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Receive failed."); + return 0; + } + else if (n < 0) // Error (including time out) + { + // TODO: If it is time-out, errno == EAGAIN + return -1; + } +#endif + total += n; } while(readFully && total < length); return total; @@ -453,6 +484,108 @@ int Socket::SetSendTimeout(int timeout) //----------------------------------------------------------------------------- +int Socket::SetReceiveBlocking(int sw) +{ + if (!this->GetConnected()) + { + return 0; + } + + // If sw == 1, timeout is set to 0 (wait until it receives message) +#if defined(_WIN32) && !defined(__CYGWIN__) + if (sw==0) + { + this->m_ReceiveTimeout = 1; + } + else + { + this->m_ReceiveTimeout = 0; + } + int len; +#else + if (sw==0) + { + this->m_ReceiveTimeout.tv_sec = 0; /* second */ + this->m_ReceiveTimeout.tv_usec = 1; /* nanosecond */ + } + else + { + this->m_ReceiveTimeout.tv_sec = 0; /* second */ + this->m_ReceiveTimeout.tv_usec = 0; /* nanosecond */ + } + socklen_t len; +#endif + if (sw==0) + { + getsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_OrigReceiveTimeout), &len); + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_ReceiveTimeout), sizeof(this->m_ReceiveTimeout)); + this->m_ReceiveTimeoutFlag = 1; + } + else if (this->m_ReceiveTimeoutFlag) + { + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_OrigReceiveTimeout), sizeof(this->m_OrigReceiveTimeout)); + this->m_ReceiveTimeoutFlag = 0; + } + + return sw; +} + + +//----------------------------------------------------------------------------- +int Socket::SetSendBlocking(int sw) +{ + if (!this->GetConnected()) + { + return 0; + } + + // If sw == 1, timeout is set to 0 (wait until it receives message) +#if defined(_WIN32) && !defined(__CYGWIN__) + if (sw==0) + { + this->m_ReceiveTimeout = 1; + } + else + { + this->m_ReceiveTimeout = 0; + } + int len; +#else + if (sw==0) + { + this->m_ReceiveTimeout.tv_sec = 0; /* second */ + this->m_ReceiveTimeout.tv_usec = 1; /* nanosecond */ + } + else + { + this->m_ReceiveTimeout.tv_sec = 0; /* second */ + this->m_ReceiveTimeout.tv_usec = 0; /* nanosecond */ + } + socklen_t len; +#endif + if (sw==0) + { + getsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_OrigSendTimeout), &len); + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_SendTimeout), sizeof(this->m_SendTimeout)); + this->m_SendTimeoutFlag = 1; + } + else if (this->m_SendTimeoutFlag) + { + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_OrigSendTimeout), sizeof(this->m_OrigSendTimeout)); + this->m_SendTimeoutFlag = 0; + } + + return sw; +} + + +//----------------------------------------------------------------------------- int Socket::GetSocketAddressAndPort(std::string& address, int& port) { struct sockaddr_in sockinfo; diff --git a/Source/igtlSocket.h b/Source/igtlSocket.h index 3b8e6a50..2327c404 100644 --- a/Source/igtlSocket.h +++ b/Source/igtlSocket.h @@ -82,6 +82,8 @@ class IGTLCommon_EXPORT Socket : public Object /// These methods send data over the socket. /// Returns 1 on success, 0 on error and raises vtkCommand::ErrorEvent. + /// SIGPIPE or other signal may be raised on systems (e.g., Sun Solaris) where + /// MSG_NOSIGNAL flag is not supported for the socket send method. int Send(const void* data, int length); /// Receive data from the socket. @@ -104,6 +106,14 @@ class IGTLCommon_EXPORT Socket : public Object /// This function should be called after opening the socket. int SetSendTimeout(int timeout); + /// Set (psuedo) non-blocking mode for recv(). When sw=1, the time out is set to + /// minimum value (1 microsecond in UNIX, 1 millisecond in Windows) for receiving. + int SetReceiveBlocking(int sw); + + /// Set (psuedo) non-blocking mode for recv(). When sw=1, the time out is set to + /// minimum value (1 microsecond in UNIX, 1 millisecond in Windows) for sending. + int SetSendBlocking(int sw); + /// Get socket address int GetSocketAddressAndPort(std::string& address, int & port); diff --git a/Source/igtlStatusMessage.h b/Source/igtlStatusMessage.h index a05bf59d..c7bd1693 100644 --- a/Source/igtlStatusMessage.h +++ b/Source/igtlStatusMessage.h @@ -23,6 +23,25 @@ namespace igtl { + +/// A class for the GET_STATUS message type. +class IGTLCommon_EXPORT GetStatusMessage: public HeaderOnlyMessageBase +{ +public: + typedef GetStatusMessage Self; + typedef HeaderOnlyMessageBase Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + igtlTypeMacro(igtl::GetStatusMessage, igtl::HeaderOnlyMessageBase); + igtlNewMacro(igtl::GetStatusMessage); + +protected: + GetStatusMessage() : HeaderOnlyMessageBase() { this->m_DefaultBodyType = "GET_STATUS"; }; + ~GetStatusMessage() {}; +}; + + /// The STATUS data type is used to notify the receiver about the current status of the sender. /// The data consist of status code in a 16-bit unsigned integer, sub code in a 64-bit integer, /// error name in a 20-byte-length character string, and a status message. The length of diff --git a/Source/igtlTransformMessage.cxx b/Source/igtlTransformMessage.cxx index 4c0d2035..49fcf8b2 100644 --- a/Source/igtlTransformMessage.cxx +++ b/Source/igtlTransformMessage.cxx @@ -21,6 +21,7 @@ namespace igtl { + TransformMessage::TransformMessage(): MessageBase() { diff --git a/Source/igtlTransformMessage.h b/Source/igtlTransformMessage.h index 0fb30b18..202c617b 100644 --- a/Source/igtlTransformMessage.h +++ b/Source/igtlTransformMessage.h @@ -22,6 +22,25 @@ namespace igtl { +/// A class for the GET_TRANS message type. +class IGTLCommon_EXPORT GetTransformMessage: public HeaderOnlyMessageBase +{ +public: + typedef GetTransformMessage Self; + typedef HeaderOnlyMessageBase Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + igtlTypeMacro(igtl::GetTransformMessage, igtl::HeaderOnlyMessageBase); + igtlNewMacro(igtl::GetTransformMessage); + +protected: + GetTransformMessage() : HeaderOnlyMessageBase() { this->m_DefaultBodyType = "GET_TRANS"; }; + ~GetTransformMessage() {}; +}; + + + /// The TRANSFORM data type is used to transfer a homogeneous linear transformation /// in 4-by-4 matrix form. One such matrix was shown earlier in equation (1). /// Note that if a device is sending only translation and rotation, then TRANSFORM diff --git a/Source/igtlutil/igtl_bind.c b/Source/igtlutil/igtl_bind.c index a5222536..2862fe3c 100644 --- a/Source/igtlutil/igtl_bind.c +++ b/Source/igtlutil/igtl_bind.c @@ -352,6 +352,7 @@ int igtl_bind_pack_normal(igtl_bind_info * info, void * byte_array) igtl_uint16 * nts; size_t wb; size_t len; + igtl_uint16 tmp16; igtl_uint64 tmp64; ptr = (char *) byte_array; @@ -366,11 +367,14 @@ int igtl_bind_pack_normal(igtl_bind_info * info, void * byte_array) /* Number of child messages */ if (igtl_is_little_endian()) { - *((igtl_uint16*) ptr) = BYTE_SWAP_INT16(info->ncmessages); + /* *((igtl_uint16*) ptr) = BYTE_SWAP_INT16(info->ncmessages); */ + tmp16 = BYTE_SWAP_INT16(info->ncmessages); + memcpy(ptr, &tmp16, sizeof(igtl_uint16)); } else { - *((igtl_uint16*) ptr) = info->ncmessages; + /* *((igtl_uint16*) ptr) = info->ncmessages; */ + memcpy(ptr, &(info->ncmessages), sizeof(igtl_uint16)); } ptr += sizeof(igtl_uint16); @@ -452,6 +456,7 @@ int igtl_bind_pack_request(igtl_bind_info * info, void * byte_array) igtl_uint16 * nts; size_t wb; size_t len; + igtl_uint16 tmp16; ptr = (char *) byte_array; nc = info->ncmessages; @@ -471,11 +476,14 @@ int igtl_bind_pack_request(igtl_bind_info * info, void * byte_array) /* Number of child messages */ if (igtl_is_little_endian()) { - *((igtl_uint16*) ptr) = BYTE_SWAP_INT16(info->ncmessages); + /* *((igtl_uint16*) ptr) = BYTE_SWAP_INT16(info->ncmessages); */ + tmp16 = BYTE_SWAP_INT16(info->ncmessages); + memcpy(ptr, &tmp16, sizeof(igtl_uint16)); } else { - *((igtl_uint16*) ptr) = info->ncmessages; + /* *((igtl_uint16*) ptr) = info->ncmessages; */ + memcpy(ptr, &(info->ncmessages), sizeof(igtl_uint16)); } ptr += sizeof(igtl_uint16); diff --git a/Source/igtlutil/igtl_capability.c b/Source/igtlutil/igtl_capability.c index 1cb16e8e..0ac83675 100644 --- a/Source/igtlutil/igtl_capability.c +++ b/Source/igtlutil/igtl_capability.c @@ -128,7 +128,7 @@ int igtl_export igtl_capability_unpack(void * byte_array, igtl_capability_info * ptr = byte_array; for (i = 0; i < ntypes; i ++) { - strncpy(info->typenames[i], ptr, IGTL_HEADER_TYPE_SIZE); + strncpy((char*)info->typenames[i], (char*)ptr, IGTL_HEADER_TYPE_SIZE); info->typenames[i][IGTL_HEADER_TYPE_SIZE] = '\0'; ptr += IGTL_HEADER_TYPE_SIZE; } @@ -157,7 +157,7 @@ int igtl_export igtl_capability_pack(igtl_capability_info * info, void * byte_ar for (i = 0; i < info->ntypes; i ++) { - strncpy(ptr, info->typenames[i], IGTL_HEADER_TYPE_SIZE); + strncpy((char*)ptr, (char*)info->typenames[i], IGTL_HEADER_TYPE_SIZE); ptr += IGTL_HEADER_TYPE_SIZE; } diff --git a/Source/igtlutil/igtl_image.c b/Source/igtlutil/igtl_image.c index c52679da..c365ce29 100644 --- a/Source/igtlutil/igtl_image.c +++ b/Source/igtlutil/igtl_image.c @@ -71,6 +71,22 @@ void igtl_export igtl_image_set_matrix(float spacing[3], float origin[3], header->matrix[11] = (igtl_float32) (origin[2]); } +void igtl_export igtl_image_set_matrix_4x4(float _matrix [4][4], igtl_image_header * header) +{ + header->matrix[0] = _matrix[0][0]; + header->matrix[1] = _matrix[0][1]; + header->matrix[2] = _matrix[0][2]; + header->matrix[3] = _matrix[1][0]; + header->matrix[4] = _matrix[1][1]; + header->matrix[5] = _matrix[1][2]; + header->matrix[6] = _matrix[2][0]; + header->matrix[7] = _matrix[2][1]; + header->matrix[8] = _matrix[2][2]; + header->matrix[9] = _matrix[0][3]; + header->matrix[10] = _matrix[1][3]; + header->matrix[11] = _matrix[2][3]; +} + void igtl_export igtl_image_get_matrix(float spacing[3], float origin[3], float norm_i[3], float norm_j[3], float norm_k[3], igtl_image_header * header) @@ -104,15 +120,26 @@ void igtl_export igtl_image_get_matrix(float spacing[3], float origin[3], spacing[0] = sqrtf(tx*tx + ty*ty + tz*tz); spacing[1] = sqrtf(sx*sx + sy*sy + sz*sz); spacing[2] = sqrtf(nx*nx + ny*ny + nz*nz); - norm_i[0] = header->matrix[0] / spacing[0]; - norm_i[1] = header->matrix[1] / spacing[0]; - norm_i[2] = header->matrix[2] / spacing[0]; - norm_j[0] = header->matrix[3] / spacing[1]; - norm_j[1] = header->matrix[4] / spacing[1]; - norm_j[2] = header->matrix[5] / spacing[1]; - norm_k[0] = header->matrix[6] / spacing[2]; - norm_k[1] = header->matrix[7] / spacing[2]; - norm_k[2] = header->matrix[8] / spacing[2]; + + if (spacing[0] != 0) + { + norm_i[0] = header->matrix[0] / spacing[0]; + norm_i[1] = header->matrix[1] / spacing[0]; + norm_i[2] = header->matrix[2] / spacing[0]; + } + if (spacing[1] != 0) + { + norm_j[0] = header->matrix[3] / spacing[1]; + norm_j[1] = header->matrix[4] / spacing[1]; + norm_j[2] = header->matrix[5] / spacing[1]; + } + if (spacing[2] != 0) + { + norm_k[0] = header->matrix[6] / spacing[2]; + norm_k[1] = header->matrix[7] / spacing[2]; + norm_k[2] = header->matrix[8] / spacing[2]; + } + origin[0] = header->matrix[9]; origin[1] = header->matrix[10]; origin[2] = header->matrix[11]; @@ -120,6 +147,29 @@ void igtl_export igtl_image_get_matrix(float spacing[3], float origin[3], } +void igtl_export igtl_image_get_matrix_4x4(float _matrix[4][4], igtl_image_header * header) +{ + _matrix[0][0] = header->matrix[0]; + _matrix[0][1] = header->matrix[1]; + _matrix[0][2] = header->matrix[2]; + _matrix[1][0] = header->matrix[3]; + _matrix[1][1] = header->matrix[4]; + _matrix[1][2] = header->matrix[5]; + _matrix[2][0] = header->matrix[6]; + _matrix[2][1] = header->matrix[7]; + _matrix[2][2] = header->matrix[8]; + + _matrix[0][3] = header->matrix[9]; + _matrix[1][3] = header->matrix[10]; + _matrix[2][3] = header->matrix[11]; + + _matrix[3][0] = 0; + _matrix[3][1] = 0; + _matrix[3][2] = 0; + _matrix[3][3] = 1; +} + + void igtl_export igtl_image_convert_byte_order(igtl_image_header * header) { int i; diff --git a/Source/igtlutil/igtl_image.h b/Source/igtlutil/igtl_image.h index 7fa939e3..e8db0567 100644 --- a/Source/igtlutil/igtl_image.h +++ b/Source/igtlutil/igtl_image.h @@ -98,6 +98,12 @@ void igtl_export igtl_image_get_matrix(float spacing[3], float origin[3], float norm_i[3], float norm_j[3], float norm_k[3], igtl_image_header * header); +/** Sets the image orientation/origin matrix in 4x4 format */ +void igtl_export igtl_image_set_matrix_4x4(float _matrix[4][4],igtl_image_header * header); + +/** Gets the image orientation/origin matrix in 4x4 format */ +void igtl_export igtl_image_get_matrix_4x4(float _matrix[4][4],igtl_image_header * header); + /** Converts endianness of each member variable in igtl_image_header from host * byte order to network byte order, or vice versa. */ void igtl_export igtl_image_convert_byte_order(igtl_image_header * header); diff --git a/Source/igtlutil/igtl_qtdata.c b/Source/igtlutil/igtl_qtdata.c index a780d12a..7d62c4d4 100644 --- a/Source/igtlutil/igtl_qtdata.c +++ b/Source/igtlutil/igtl_qtdata.c @@ -60,7 +60,7 @@ void igtl_export igtl_stt_qtdata_convert_byte_order(igtl_stt_qtdata* stt_qtdata) void igtl_export igtl_rts_qtdata_convert_byte_order(igtl_rts_qtdata* rts_qtdata) { - // do nothing + /* do nothing */ } diff --git a/Source/igtlutil/igtl_sensor.c b/Source/igtlutil/igtl_sensor.c index fe1c4ad4..32eac1e0 100644 --- a/Source/igtlutil/igtl_sensor.c +++ b/Source/igtlutil/igtl_sensor.c @@ -37,7 +37,7 @@ void igtl_export igtl_sensor_convert_byte_order(igtl_sensor_header* header, igtl if (igtl_is_little_endian()) { - larray = (int) header->larray; // NOTE: larray is 8-bit (doesn't depend on endianness) + larray = (int) header->larray; /* NOTE: larray is 8-bit (doesn't depend on endianness) */ header->unit = BYTE_SWAP_INT64(header->unit); tmp = (igtl_uint64*) data; diff --git a/Source/igtlutil/igtl_tdata.c b/Source/igtlutil/igtl_tdata.c index b01f80f1..7542857e 100644 --- a/Source/igtlutil/igtl_tdata.c +++ b/Source/igtlutil/igtl_tdata.c @@ -54,7 +54,7 @@ void igtl_export igtl_stt_tdata_convert_byte_order(igtl_stt_tdata* stt_tdata) void igtl_export igtl_rts_tdata_convert_byte_order(igtl_rts_tdata* rts_tdata) { - // do nothing + /* do nothing */ } diff --git a/Source/igtlutil/igtl_types.h b/Source/igtlutil/igtl_types.h index 57935ea2..af67ba41 100644 --- a/Source/igtlutil/igtl_types.h +++ b/Source/igtlutil/igtl_types.h @@ -20,7 +20,7 @@ /* 8-bit integer type */ #if IGTL_SIZEOF_CHAR == 1 typedef unsigned char igtl_uint8; - typedef char igtl_int8; + typedef signed char igtl_int8; #else # error "No native data type can represent an 8-bit integer." #endif diff --git a/Source/igtlutil/igtl_unit.c b/Source/igtlutil/igtl_unit.c index 1100d83a..1410b648 100644 --- a/Source/igtlutil/igtl_unit.c +++ b/Source/igtlutil/igtl_unit.c @@ -74,8 +74,8 @@ int igtl_export igtl_unit_unpack(igtl_unit pack, igtl_unit_data* data) /* Units */ for (i = 0; i < 6; i ++) { - data->unit[i] = (igtl_uint8) (pack >> (10*(5-i) + 4)) && 0x3F; - data->exp[i] = (igtl_uint8) (pack >> (10*(5-i))) && 0x0F; + data->unit[i] = (igtl_uint8) (pack >> (10*(5-i) + 4)) & 0x3F; + data->exp[i] = (igtl_uint8) (pack >> (10*(5-i))) & 0x0F; /* Convert signed value in exponent field from 4-bit to 8-bit */ if (data->exp[i] & 0x08) { diff --git a/Testing/igtlutil/igtl_bind_test.c b/Testing/igtlutil/igtl_bind_test.c index 3cbb7811..f03ae46e 100644 --- a/Testing/igtlutil/igtl_bind_test.c +++ b/Testing/igtlutil/igtl_bind_test.c @@ -24,6 +24,7 @@ #include "igtl_transform.h" #include #include +#include #define EXIT_SUCCESS 0 diff --git a/Testing/igtlutil/igtl_capability_test.c b/Testing/igtlutil/igtl_capability_test.c index dedd8611..69676785 100644 --- a/Testing/igtlutil/igtl_capability_test.c +++ b/Testing/igtlutil/igtl_capability_test.c @@ -15,6 +15,7 @@ =========================================================================*/ #include +#include #include "igtl_types.h" #include "igtl_header.h" #include "igtl_capability.h" @@ -53,10 +54,10 @@ int main( int argc, char * argv [] ) return EXIT_FAILURE; } - strcpy(info.typenames[0], "IMAGE"); - strcpy(info.typenames[1], "GET_IMAGE"); - strcpy(info.typenames[2], "TRANSFORM"); - strcpy(info.typenames[3], "GET_TRANS"); + strcpy((char*)info.typenames[0], "IMAGE"); + strcpy((char*)info.typenames[1], "GET_IMAGE"); + strcpy((char*)info.typenames[2], "TRANSFORM"); + strcpy((char*)info.typenames[3], "GET_TRANS"); igtl_capability_pack(&info, message.body); diff --git a/Testing/igtlutil/igtl_colortable_test.c b/Testing/igtlutil/igtl_colortable_test.c index 654870a7..da9e0fe9 100644 --- a/Testing/igtlutil/igtl_colortable_test.c +++ b/Testing/igtlutil/igtl_colortable_test.c @@ -15,6 +15,8 @@ =========================================================================*/ #include +#include + #include "igtl_types.h" #include "igtl_header.h" #include "igtl_colortable.h" diff --git a/Testing/igtlutil/igtl_image_test.c b/Testing/igtlutil/igtl_image_test.c index ccfb8435..27a79d51 100644 --- a/Testing/igtlutil/igtl_image_test.c +++ b/Testing/igtlutil/igtl_image_test.c @@ -15,6 +15,7 @@ =========================================================================*/ #include +#include #include "igtl_types.h" #include "igtl_header.h" diff --git a/Testing/igtlutil/igtl_imgmeta_test.c b/Testing/igtlutil/igtl_imgmeta_test.c index 20cef44a..1bce6b4c 100644 --- a/Testing/igtlutil/igtl_imgmeta_test.c +++ b/Testing/igtlutil/igtl_imgmeta_test.c @@ -15,6 +15,7 @@ =========================================================================*/ #include +#include #include "igtl_types.h" #include "igtl_header.h" #include "igtl_imgmeta.h" diff --git a/Testing/igtlutil/igtl_lbmeta_test.c b/Testing/igtlutil/igtl_lbmeta_test.c index 499253f1..eaa8807c 100644 --- a/Testing/igtlutil/igtl_lbmeta_test.c +++ b/Testing/igtlutil/igtl_lbmeta_test.c @@ -15,6 +15,7 @@ =========================================================================*/ #include +#include #include "igtl_types.h" #include "igtl_header.h" #include "igtl_lbmeta.h" diff --git a/Testing/igtlutil/igtl_ndarray_test.c b/Testing/igtlutil/igtl_ndarray_test.c index f184fec7..63bf7ad8 100644 --- a/Testing/igtlutil/igtl_ndarray_test.c +++ b/Testing/igtlutil/igtl_ndarray_test.c @@ -21,6 +21,7 @@ #include "igtl_util.h" #include #include +#include #define EXIT_SUCCESS 0 diff --git a/Testing/igtlutil/igtl_point_test.c b/Testing/igtlutil/igtl_point_test.c index 4d5bf2b6..a8990cfc 100644 --- a/Testing/igtlutil/igtl_point_test.c +++ b/Testing/igtlutil/igtl_point_test.c @@ -15,6 +15,8 @@ =========================================================================*/ #include +#include + #include "igtl_types.h" #include "igtl_header.h" #include "igtl_point.h" diff --git a/Testing/igtlutil/igtl_polydata_test.c b/Testing/igtlutil/igtl_polydata_test.c index c4f7965d..57d7538f 100644 --- a/Testing/igtlutil/igtl_polydata_test.c +++ b/Testing/igtlutil/igtl_polydata_test.c @@ -20,6 +20,7 @@ #include "igtl_util.h" #include #include +#include #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 diff --git a/Testing/igtlutil/igtl_string_test.c b/Testing/igtlutil/igtl_string_test.c index 054349b9..8257f141 100644 --- a/Testing/igtlutil/igtl_string_test.c +++ b/Testing/igtlutil/igtl_string_test.c @@ -60,7 +60,7 @@ int main( int argc, char * argv [] ) /* Set dummy string header and values */ message.string_header.encoding = 3; message.string_header.length = IGTL_STRING_TEST_STRING_LEN; - strncpy(message.string, IGTL_STRING_TEST_STRING, IGTL_STRING_TEST_STRING_LEN); + strncpy((char*)message.string, IGTL_STRING_TEST_STRING, IGTL_STRING_TEST_STRING_LEN); igtl_string_convert_byte_order(&(message.string_header)); /* Set header */ diff --git a/Testing/igtlutil/igtl_tdata_test.c b/Testing/igtlutil/igtl_tdata_test.c index e930c1ad..e55609f2 100644 --- a/Testing/igtlutil/igtl_tdata_test.c +++ b/Testing/igtlutil/igtl_tdata_test.c @@ -15,6 +15,7 @@ =========================================================================*/ #include +#include #include "igtl_types.h" #include "igtl_header.h" #include "igtl_tdata.h" diff --git a/Testing/igtlutil/igtl_test_data_polydata.h b/Testing/igtlutil/igtl_test_data_polydata.h index 501c5683..42d1e877 100644 --- a/Testing/igtlutil/igtl_test_data_polydata.h +++ b/Testing/igtlutil/igtl_test_data_polydata.h @@ -76,7 +76,7 @@ char test_polydata_message_body[] = { 0x3f, 0x80, 0x00, 0x00, /* Point #7 - y*/ 0x3f, 0x80, 0x00, 0x00, /* Point #7 - z*/ - /* No vertices * + /* No vertices */ /* No lines */ diff --git a/Testing/igtlutil/igtl_trajectory_test.c b/Testing/igtlutil/igtl_trajectory_test.c index 15d27814..0825767c 100644 --- a/Testing/igtlutil/igtl_trajectory_test.c +++ b/Testing/igtlutil/igtl_trajectory_test.c @@ -15,6 +15,7 @@ =========================================================================*/ #include +#include #include "igtl_types.h" #include "igtl_header.h" #include "igtl_trajectory.h" diff --git a/igtlConfigure.h.in b/igtlConfigure.h.in index 0b89b46c..ae1b98e3 100644 --- a/igtlConfigure.h.in +++ b/igtlConfigure.h.in @@ -1,6 +1,6 @@ /*========================================================================= - Program: Open IGT Link Library + Program: OpenIGTLink Library Module: $HeadURL: http://svn.na-mic.org/NAMICSandBox/trunk/OpenIGTLink/igtlConfigure.h.in $ Language: C Date: $Date: 2010-06-09 16:16:36 -0400 (Wed, 09 Jun 2010) $ @@ -35,6 +35,8 @@ #cmakedefine OpenIGTLink_USE_WIN32_THREADS #cmakedefine OpenIGTLink_USE_SPROC #cmakedefine OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T +#cmakedefine OpenIGTLink_HAVE_STRNLEN + #define OpenIGTLink_PROTOCOL_VERSION @OpenIGTLink_PROTOCOL_VERSION@ #endif /*__IGTL_CONFIGURE_H*/