Difference between revisions of "OpenIGTLink/Library/Tutorial"

From NAMIC Wiki
Jump to: navigation, search
 
(54 intermediate revisions by 3 users not shown)
Line 2: Line 2:
 
<div class="floatright">__TOC__</div>
 
<div class="floatright">__TOC__</div>
  
=Implementing Open IGT Link using igtlutil=
+
=Two approaches to use the Open IGT Link=
The igtlutil c functions are available from Source/igtlutil in the Open IGT Link Library.
 
  
The followings are example codes to create Open IGT Link message.
+
==Using the low-level C library==
 +
The library has been built on the low-level C-library called '''igtlutil''', which is a collection of several data structures with supporting functions for data serialization, endian conversion and cyclic redundancy check, written in ANSI C. The developers can directly use this low-level C-library from their programs. The library is particularly useful to develop embedded or old systems that do not have any modern C++ compiler. The usage of igtlutil can be found in [[OpenIGTLink/Tutorial/igtlutil | the igtlutil tutorial page]].
  
Include declarations for transformation data:
+
==Using the C++ message classes==
  #include "igtl_util.h"
+
The library provides much more simple, portable and safer ways to generate standard Open IGT Link messages using C++ classes. The developers can easily add classes to serialize/deserialize their own data types, by inheriting the base message class. It also provides the multi-platform TCP socket / threading classes; the developers can write multi-platform IGT applications, which communicate with other IGT devices and software, with the Open IGT Link library. Those classes are implemented based on Win32 socket /  thread API for Windows and BSD socket / POSIX Thread API for Linux and Mac OS X, and have been tested on those environments.
  #include "igtl_header.h"
 
  #include "igtl_transform.h"
 
  
Transform package creation:
+
<BR>
  /********** pack data body **********/
+
Please refer [[OpenIGTLink/Approaches]] to choose your approach.
  igtl_float32 transform[12];
+
 
 +
<BR>
 +
 
 +
=Setting up the library=
 +
Please refer to[[OpenIGTLink/Library/Build | the Open IGT Link library building instruction]].
 +
 
 +
<BR>
 +
 
 +
=Using the low-level C library (igtlutil)=
 +
 
 +
The code snippet can be found in [[OpenIGTLink/Tutorial/igtlutil | igtlutil tutorial page]].
 +
 
 +
<BR>
 +
 
 +
=Using the Open IGT Link Library C++ interface=
 +
 
 +
==Get the example code==
 +
The example code is available in the Examples/ directory of Open IGT Link library. The instruction is available on [[OpenIGTLink/Library | the Open IGT Link Library page]].
 +
 
 +
{|border="1" cellpadding="2"
 +
| style="width:25%; background:#5EAE85"|Example Name
 +
| style="width:25%; background:#5EAE85"|Directory
 +
| style="width:50%; background:#5EAE85"|Description
 +
|-
 +
|style="width:25%; background:#8EDEB5"| TrackerClient.cxx
 +
||Example/Tracker
 +
||Example to send dummy tracking; works as a TCP client.
 +
|-
 +
|style="width:25%; background:#8EDEB5"| TrackerServer.cxx
 +
||Example/Tracker
 +
||Example to send dummy tracking; works as a TCP server.
 +
|-
 +
|style="width:25%; background:#8EDEB5"| ReceiveServer.cxx
 +
||Example/Receiver
 +
||Example to receive tracking data; works as a TCP server.
 +
|-
 +
|style="width:25%; background:#8EDEB5"| ImagerClient.cxx (to be added)
 +
||Example/Imager
 +
||Example to send image data; works as a TCP client
 +
|-
 +
|style="width:25%; background:#8EDEB5"| ImagerServer.cxx (to be added)
 +
||Example/Imager
 +
||Example to send image data; works as a TCP client
 +
|}
 +
 
 +
==Code snippet from Tracker Client program==
 +
 
 +
The code "[http://svn.na-mic.org/NAMICSandBox/trunk/OpenIGTLink/Examples/Tracker/TrackerClient.cxx Tracker/TrackerClient.cxx]" demonstrates how to create open igt link message, establish connection with the Open IGT Link server, then repeat sending coordinate data to the server, using Open IGT Link Library.
 +
 
 +
First, establish connection with server (ip: 192.168.0.1, port number: 18944) using igtl::ClientSocket class:
 +
 
 +
  igtl::ClientSocket::Pointer socket;
 +
  socket = igtl::ClientSocket::New();
 +
  int r = socket->ConnectToServer("192.168.0.1", 18944);
 
    
 
    
   transform[0] = tx;
+
   if (r != 0)
   transform[1] = ty;
+
    {
   transform[2] = tz;
+
    //
   transform[3] = sx;
+
    // do error handling
   transform[4] = sy;
+
    //
   transform[5] = sz;
+
    }
   transform[6] = nx;
+
 
   transform[7] = ny;
+
Prepare a class instance for the Open IGT Link message:
  transform[8] = nz;
+
 
   transform[9] = px;
+
  igtl::TransformMessage::Pointer transMsg;
   transform[10] = py;
+
   transMsg = igtl::TransformMessage::New();
   transform[11] = pz;
+
 
 +
Set the Open IGT Link device name:
 +
 
 +
   transMsg->SetDeviceName("Tracker");
 +
 
 +
Substitute matrix into the Matrix4x4 class:
 +
 
 +
   igtl::Matrix4x4 matrix;
 +
   GetRandomTestMatrix(matrix);
 +
 
 +
Set the matrix to the message class:
 +
 
 +
   transMsg->SetMatrix(matrix);
 +
 
 +
Pack the data. This member function generates byte stream formatted in Open IGT Link format.
 +
 
 +
   transMsg->Pack();
 +
 
 +
Send data through TCP/IP socket connection:
 +
 
 +
   socket->Send(transMsg->GetPackPointer(), transMsg->GetPackSize());
 +
 
 +
The igtl::ClientSocket class can be replaced by other socket library.
 +
 
 +
==Code snippet from Receiver Server program==
 +
 
 +
In contrast to the example above, "[http://svn.na-mic.org/NAMICSandBox/trunk/OpenIGTLink/Examples/Receiver/ReceiveServer.cxx Examlpes/Receiver/ReceiveServer.cxx] demonstrates how to wait for the connection from the client and receive Open IGT Link messages, using the Open IGT Link Library C++ interface.
 +
 
 +
First, prepare server socket to wait for the client to connect. Suppose the port number is 18944.
 +
 
 +
   igtl::ServerSocket::Pointer serverSocket;
 +
   serverSocket = igtl::ServerSocket::New();
 +
   serverSocket->CreateServer(port);
 
    
 
    
   igtl_transform_convert_byte_order(transform);  /* convert endian if necessary */
+
   igtl::ClientSocket::Pointer socket;
 +
  socket = serverSocket->WaitForConnection(30000);  // wait for 30000 milliseconds (30 seconds)
 +
 
 +
If the client connects to the program, the pointer to the socket instance is substituted into the 'socket' pointer. You can check if the socket pointer has been substituted by calling:
 
    
 
    
  /********** general header **********/
+
    if (socket.IsNotNull()) // if client connected
  igtl_header header;
+
      {
  igtl_uint64 crc = crc64(0, 0, 0LL);          /* initial crc */
+
      // start receiving data
  header.version  = IGTL_HEADER_VERSION;
+
 
  header.timestamp = 0;
+
Now the connection has been established. To receive a message header, create igtl::MessageHeader class instance.
  header.body_size = IGTL_TRANSFORM_SIZE;
+
 
  header.crc      = crc64((unsigned char*)transform, IGTL_TRANSFORM_SIZE, crc);
+
        igtl::MessageHeader::Pointer headerMsg;
 
+
        headerMsg = igtl::MessageHeader::New();
  strncpy(header.name, "TRANSFORM", 12);      /* Device Type: should be "TRANSFORM" */
+
 
  strncpy(header.device_name, "Tracker", 20);   /* Device name */
+
Usually, programs start looping at this point. At the beginning of the loop, the headerMsg class must be initialized.
 
+
 
  igtl_header_convert_byte_order(h);  /* convert endian if necessary */
+
        headerMsg->InitPack();
 +
 
 +
Then call Receive() function to get byte stream from the socket connection. The Receive() function returns the size of the received data. You can check the result by comparing returned value with header size (can be obtained by using headerMsg->GetPackSize())
 +
 
 +
        int r = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize());
 +
 
 +
After receiving the header, unpack (deserialize) it to extract the header information.
 +
 
 +
        headerMsg->Unpack();
 +
 
 +
The message type can be accessed by headerMsg->GetDeviceType() function. When you write message handler for TRANSFORM type message, you may compare the type name like:
 +
 
 +
        if (strcmp(headerMsg->GetDeviceType(), "TRANSFORM") == 0)
 +
          {
 +
          // Message body handler for TRANSFORM
 +
 
 +
To receive TRANSFORM message, setup a igtl::TransformMessage class instance
 +
 
 +
          igtl::TransformMessage::Pointer transMsg;
 +
          transMsg = igtl::TransformMessage::New();
 +
 
 +
then put the header information to the transMsg. By calling AllocatePack() function after setting the header, the memory area  to receive the message body is allocated.
 +
 
 +
          transMsg->SetMessageHeader(headerMsg);
 +
          transMsg->AllocatePack();
 +
 
 +
Receive the message body
 +
 
 +
          socket->Receive(transMsg->GetPackBodyPointer(), transMsg->GetPackBodySize());
 +
 
 +
Unpack (deserialize) the message body. If 1 is specified, Unpack() function performs cyclic redundancy check (CRC) and unpack the data only if CRC passes. If the data is successfully unpacked, the Unpack() function returns a value with igtl::MessageHeader::UNPACK_BODY bit.
  
Then send package (in case of BSD socket)
+
          int c = transMsg->Unpack(1);
  send(sock, (void*) &header, IGTL_HEADER_SIZE, 0);
+
          if (c & igtl::MessageHeader::UNPACK_BODY)  
  send(sock, (void*) transform, IGTL_TRANSFORM_SIZE, 0);
+
            {
 +
            // if CRC check is OK. Read transform data.
 +
              igtl::Matrix4x4 matrix;
 +
              transMsg->GetMatrix(matrix);
 +
              igtl::PrintMatrix(matrix);
 +
            }

Latest revision as of 20:35, 16 December 2008

Home < OpenIGTLink < Library < Tutorial

<< OpenIGTLink

Two approaches to use the Open IGT Link

Using the low-level C library

The library has been built on the low-level C-library called igtlutil, which is a collection of several data structures with supporting functions for data serialization, endian conversion and cyclic redundancy check, written in ANSI C. The developers can directly use this low-level C-library from their programs. The library is particularly useful to develop embedded or old systems that do not have any modern C++ compiler. The usage of igtlutil can be found in the igtlutil tutorial page.

Using the C++ message classes

The library provides much more simple, portable and safer ways to generate standard Open IGT Link messages using C++ classes. The developers can easily add classes to serialize/deserialize their own data types, by inheriting the base message class. It also provides the multi-platform TCP socket / threading classes; the developers can write multi-platform IGT applications, which communicate with other IGT devices and software, with the Open IGT Link library. Those classes are implemented based on Win32 socket / thread API for Windows and BSD socket / POSIX Thread API for Linux and Mac OS X, and have been tested on those environments.


Please refer OpenIGTLink/Approaches to choose your approach.


Setting up the library

Please refer to the Open IGT Link library building instruction.


Using the low-level C library (igtlutil)

The code snippet can be found in igtlutil tutorial page.


Using the Open IGT Link Library C++ interface

Get the example code

The example code is available in the Examples/ directory of Open IGT Link library. The instruction is available on the Open IGT Link Library page.

Example Name Directory Description
TrackerClient.cxx Example/Tracker Example to send dummy tracking; works as a TCP client.
TrackerServer.cxx Example/Tracker Example to send dummy tracking; works as a TCP server.
ReceiveServer.cxx Example/Receiver Example to receive tracking data; works as a TCP server.
ImagerClient.cxx (to be added) Example/Imager Example to send image data; works as a TCP client
ImagerServer.cxx (to be added) Example/Imager Example to send image data; works as a TCP client

Code snippet from Tracker Client program

The code "Tracker/TrackerClient.cxx" demonstrates how to create open igt link message, establish connection with the Open IGT Link server, then repeat sending coordinate data to the server, using Open IGT Link Library.

First, establish connection with server (ip: 192.168.0.1, port number: 18944) using igtl::ClientSocket class:

 igtl::ClientSocket::Pointer socket;
 socket = igtl::ClientSocket::New();
 int r = socket->ConnectToServer("192.168.0.1", 18944);
 
 if (r != 0)
   {
   //
   // do error handling
   //
   }

Prepare a class instance for the Open IGT Link message:

 igtl::TransformMessage::Pointer transMsg;
 transMsg = igtl::TransformMessage::New();

Set the Open IGT Link device name:

 transMsg->SetDeviceName("Tracker");

Substitute matrix into the Matrix4x4 class:

 igtl::Matrix4x4 matrix;
 GetRandomTestMatrix(matrix);

Set the matrix to the message class:

 transMsg->SetMatrix(matrix);

Pack the data. This member function generates byte stream formatted in Open IGT Link format.

 transMsg->Pack();

Send data through TCP/IP socket connection:

 socket->Send(transMsg->GetPackPointer(), transMsg->GetPackSize());

The igtl::ClientSocket class can be replaced by other socket library.

Code snippet from Receiver Server program

In contrast to the example above, "Examlpes/Receiver/ReceiveServer.cxx demonstrates how to wait for the connection from the client and receive Open IGT Link messages, using the Open IGT Link Library C++ interface.

First, prepare server socket to wait for the client to connect. Suppose the port number is 18944.

 igtl::ServerSocket::Pointer serverSocket;
 serverSocket = igtl::ServerSocket::New();
 serverSocket->CreateServer(port);
 
 igtl::ClientSocket::Pointer socket;
 socket = serverSocket->WaitForConnection(30000);  // wait for 30000 milliseconds (30 seconds)

If the client connects to the program, the pointer to the socket instance is substituted into the 'socket' pointer. You can check if the socket pointer has been substituted by calling:

   if (socket.IsNotNull()) // if client connected
     {
     // start receiving data

Now the connection has been established. To receive a message header, create igtl::MessageHeader class instance.

       igtl::MessageHeader::Pointer headerMsg;
       headerMsg = igtl::MessageHeader::New();

Usually, programs start looping at this point. At the beginning of the loop, the headerMsg class must be initialized.

       headerMsg->InitPack();

Then call Receive() function to get byte stream from the socket connection. The Receive() function returns the size of the received data. You can check the result by comparing returned value with header size (can be obtained by using headerMsg->GetPackSize())

       int r = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize());

After receiving the header, unpack (deserialize) it to extract the header information.

       headerMsg->Unpack();

The message type can be accessed by headerMsg->GetDeviceType() function. When you write message handler for TRANSFORM type message, you may compare the type name like:

       if (strcmp(headerMsg->GetDeviceType(), "TRANSFORM") == 0)
         {
         // Message body handler for TRANSFORM

To receive TRANSFORM message, setup a igtl::TransformMessage class instance

         igtl::TransformMessage::Pointer transMsg;
         transMsg = igtl::TransformMessage::New();

then put the header information to the transMsg. By calling AllocatePack() function after setting the header, the memory area to receive the message body is allocated.

         transMsg->SetMessageHeader(headerMsg);
         transMsg->AllocatePack();

Receive the message body

         socket->Receive(transMsg->GetPackBodyPointer(), transMsg->GetPackBodySize());

Unpack (deserialize) the message body. If 1 is specified, Unpack() function performs cyclic redundancy check (CRC) and unpack the data only if CRC passes. If the data is successfully unpacked, the Unpack() function returns a value with igtl::MessageHeader::UNPACK_BODY bit.

         int c = transMsg->Unpack(1);
         if (c & igtl::MessageHeader::UNPACK_BODY) 
           {
           // if CRC check is OK. Read transform data.
             igtl::Matrix4x4 matrix;
             transMsg->GetMatrix(matrix);
             igtl::PrintMatrix(matrix);
           }