Skip to content

Commit e8ab82f

Browse files
committed
ENH: Adds an option to build an OpenIGTLink server for RF data
This has been created as an alternative to the Plus implementation, which currently does not return all of the RF data
1 parent c76bef7 commit e8ab82f

5 files changed

Lines changed: 365 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ include( CTest )
3131

3232
# Options
3333
option( BUILD_APPLICATIONS "Build applications" OFF )
34+
option( BUILD_SERVERS "Build OpenIGTLink Servers" OFF)
3435

3536
# External dependencies
3637
find_path( IntersonArraySDK_DIR
@@ -73,6 +74,10 @@ if( BUILD_APPLICATIONS )
7374
add_subdirectory( app )
7475
endif()
7576

77+
if( BUILD_SERVERS )
78+
add_subdirectory( openigtlink )
79+
endif()
80+
7681
# Install Interson libraries
7782
install( FILES ${IntersonArraySDK_LIBRARY}
7883
DESTINATION ${INSTALL_BIN_DIR} COMPONENT Runtime

openigtlink/CMakeLists.txt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
##############################################################################
2+
#
3+
# Library: IntersonArraySDK
4+
#
5+
# Copyright Kitware Inc. 28 Corporate Drive,
6+
# Clifton Park, NY, 12065, USA.
7+
#
8+
# All rights reserved.
9+
#
10+
# Licensed under the Apache License, Version 2.0 (the "License");
11+
# you may not use this file except in compliance with the License.
12+
# You may obtain a copy of the License at
13+
#
14+
# http://www.apache.org/licenses/LICENSE-2.0
15+
#
16+
# Unless required by applicable law or agreed to in writing, software
17+
# distributed under the License is distributed on an "AS IS" BASIS,
18+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19+
# See the License for the specific language governing permissions and
20+
# limitations under the License.
21+
#
22+
##############################################################################
23+
find_package( SlicerExecutionModel REQUIRED )
24+
include( ${SlicerExecutionModel_USE_FILE} )
25+
26+
find_package(OpenIGTLink REQUIRED)
27+
include(${OpenIGTLink_USE_FILE})
28+
29+
30+
SEMMacroBuildCLI(
31+
NAME IntersonArrayServerRF
32+
TARGET_LIBRARIES ${ITK_LIBRARIES}
33+
IntersonArrayCxx
34+
OpenIGTLink
35+
INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR}/include
36+
${PROJECT_BINARY_DIR}/include
37+
)
38+
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
/*=========================================================================
2+
3+
Library: IntersonArray
4+
5+
Copyright Kitware Inc. 28 Corporate Drive,
6+
Clifton Park, NY, 12065, USA.
7+
8+
All rights reserved.
9+
10+
Licensed under the Apache License, Version 2.0 ( the "License" );
11+
you may not use this file except in compliance with the License.
12+
You may obtain a copy of the License at
13+
14+
http://www.apache.org/licenses/LICENSE-2.0
15+
16+
Unless required by applicable law or agreed to in writing, software
17+
distributed under the License is distributed on an "AS IS" BASIS,
18+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19+
See the License for the specific language governing permissions and
20+
limitations under the License.
21+
22+
=========================================================================*/
23+
#include <Windows.h> // Sleep
24+
25+
#include "IntersonArrayCxxImagingContainer.h"
26+
#include "IntersonArrayCxxControlsHWControls.h"
27+
#include "igtlImageMessage.h"
28+
#include "igtlServerSocket.h"
29+
30+
#include "IntersonArrayServerRFCLP.h"
31+
32+
typedef IntersonArrayCxx::Imaging::Container ContainerType;
33+
typedef ContainerType::RFImagePixelType PixelType;
34+
bool running;
35+
36+
BOOL WINAPI consoleHandler(DWORD signal) {
37+
38+
if (signal == CTRL_C_EVENT)
39+
{
40+
running = false;
41+
}
42+
43+
return TRUE;
44+
}
45+
46+
struct CallbackClientData
47+
{
48+
int FrameIndex;
49+
igtl::Socket * socket;
50+
igtl::ImageMessage * imgMsg;
51+
igtl::TimeStamp * ts;
52+
};
53+
54+
void __stdcall pasteIntoImage( PixelType * buffer, void * clientData )
55+
{
56+
CallbackClientData * callbackClientData =
57+
static_cast< CallbackClientData * >( clientData );
58+
59+
igtl::ImageMessage * message = callbackClientData->imgMsg;
60+
igtl::Socket * socket = callbackClientData->socket;
61+
igtl::TimeStamp * ts = callbackClientData->ts;
62+
63+
const int framePixels = ContainerType::MAX_RFSAMPLES * ContainerType::NBOFLINES;
64+
++(callbackClientData->FrameIndex);
65+
66+
message->SetMessageID(callbackClientData->FrameIndex);
67+
ts->GetTime();
68+
igtlUint32 sec;
69+
igtlUint32 nsec;
70+
ts->GetTimeStamp(&sec, &nsec);
71+
message->SetTimeStamp(sec, nsec);
72+
73+
std::memcpy(message->GetScalarPointer(), buffer, framePixels * sizeof(PixelType));
74+
75+
if (!socket)
76+
{
77+
return;
78+
}
79+
80+
message->Pack();
81+
socket->Send(message->GetPackPointer(), message->GetPackSize());
82+
}
83+
84+
int main( int argc, char * argv[] )
85+
{
86+
PARSE_ARGS;
87+
88+
typedef IntersonArrayCxx::Controls::HWControls HWControlsType;
89+
IntersonArrayCxx::Controls::HWControls hwControls;
90+
91+
int ret = EXIT_SUCCESS;
92+
93+
int steering = 0;
94+
typedef HWControlsType::FoundProbesType FoundProbesType;
95+
FoundProbesType foundProbes;
96+
hwControls.FindAllProbes( foundProbes );
97+
if( foundProbes.empty() )
98+
{
99+
std::cerr << "Could not find the probe." << std::endl;
100+
return EXIT_FAILURE;
101+
}
102+
hwControls.FindMyProbe( 0 );
103+
const unsigned int probeId = hwControls.GetProbeID();
104+
if( probeId == 0 )
105+
{
106+
std::cerr << "Could not find the probe." << std::endl;
107+
return EXIT_FAILURE;
108+
}
109+
110+
HWControlsType::FrequenciesType frequencies;
111+
hwControls.GetFrequency( frequencies );
112+
113+
HWControlsType::FocusType focuses;
114+
hwControls.GetFocus(focuses);
115+
116+
if( !hwControls.SetFrequencyAndFocus( frequencyIndex, focusIndex,
117+
steering ) )
118+
{
119+
std::cerr << "Could not set the frequency and focus." << std::endl;
120+
return EXIT_FAILURE;
121+
}
122+
123+
if( !hwControls.SendHighVoltage( highVoltage, highVoltage ) )
124+
{
125+
std::cerr << "Could not set the high voltage." << std::endl;
126+
return EXIT_FAILURE;
127+
}
128+
if( !hwControls.EnableHighVoltage() )
129+
{
130+
std::cerr << "Could not enable high voltage." << std::endl;
131+
return EXIT_FAILURE;
132+
}
133+
134+
hwControls.DisableHardButton();
135+
ContainerType container;
136+
container.SetHWControls(&hwControls);
137+
138+
const int height_lines = hwControls.GetLinesPerArray();
139+
std::cout << "Lines per array: " << height_lines << std::endl;
140+
const int width_samples = ContainerType::MAX_RFSAMPLES;
141+
std::cout << "Max RF samples: " << width_samples << std::endl;
142+
const double ns = ContainerType::MAX_RFSAMPLES; // number of samples
143+
const double fs = 30000; // [kHz]=[samples/ms] - sampling frequency
144+
const double depth = sos * ( ns - 1 ) / ( 2 * fs );
145+
const double depthCfm = depth/2;
146+
std::cout << "Depth: " << depth << "mm" << std::endl;
147+
std::cout << std::endl;
148+
149+
container.SetRFData( true );
150+
container.IdleInitScanConverter( depth, width_samples, height_lines, probeId,
151+
steering, depthCfm, false, false, 0, false );
152+
container.HardInitScanConverter( depth, width_samples, height_lines, steering,
153+
depthCfm );
154+
155+
CallbackClientData clientData;
156+
clientData.FrameIndex = 0;
157+
158+
// size parameters
159+
const short frameRate = hwControls.GetProbeFrameRate();
160+
int size[] = { ContainerType::MAX_RFSAMPLES, ContainerType::NBOFLINES, 1 }; // image dimension
161+
float spacing[] = { sos / (2 * fs), 38.0 / (height_lines - 1), 1.0 / frameRate }; // spacing (mm/pixel)
162+
int svsize[] = { ContainerType::MAX_RFSAMPLES, ContainerType::NBOFLINES, 1 }; // sub-volume size
163+
int svoffset[] = { 0, 0, 0 }; // sub-volume offset
164+
int scalarType = igtl::ImageMessage::TYPE_INT16;// scalar type
165+
166+
//------------------------------------------------------------
167+
// Create a new IMAGE type message
168+
igtl::ImageMessage::Pointer imgMsg = igtl::ImageMessage::New();
169+
imgMsg->SetDimensions(size);
170+
imgMsg->SetSpacing(spacing);
171+
imgMsg->SetScalarType(scalarType);
172+
imgMsg->SetDeviceName("IntersonRF");
173+
imgMsg->SetSubVolume(svsize, svoffset);
174+
imgMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2);
175+
IANA_ENCODING_TYPE codingScheme = IANA_TYPE_US_ASCII;
176+
177+
//Add meta data here
178+
imgMsg->SetMetaDataElement("Frequency (MHz)", codingScheme, std::to_string(frequencies[frequencyIndex]));
179+
imgMsg->SetMetaDataElement("Focus (mm)", codingScheme, std::to_string(focuses[focusIndex]));
180+
imgMsg->SetMetaDataElement("High voltage", codingScheme, std::to_string(highVoltage));
181+
imgMsg->SetMetaDataElement("SOS", codingScheme, std::to_string(sos));
182+
imgMsg->SetMetaDataElement("FPS", codingScheme, std::to_string(frameRate));
183+
imgMsg->SetMetaDataElement("Steering", codingScheme, std::to_string(steering));
184+
imgMsg->SetMetaDataElement("Image Type", codingScheme, "RF");
185+
imgMsg->SetMetaDataElement("Timestamp seconds", codingScheme, "0");
186+
imgMsg->SetMetaDataElement("Timestamp nseconds", codingScheme, "0");
187+
188+
imgMsg->AllocateScalars();
189+
imgMsg->SetEndian(igtl::ImageMessage::ENDIAN_LITTLE);
190+
igtl::Matrix4x4 matrix;
191+
matrix[0][0] = 0.0; matrix[1][0] = -1.0; matrix[2][0] = 0.0; matrix[3][0] = 0.0;
192+
matrix[0][1] = 1.0; matrix[1][1] = 0.0; matrix[2][1] = 0.0; matrix[3][1] = 0.0;
193+
matrix[0][2] = 0.0; matrix[1][2] = 0.0; matrix[2][2] = 1.0; matrix[3][2] = 0.0;
194+
matrix[0][3] = 0.0; matrix[1][3] = 0.0; matrix[2][3] = 0.0; matrix[3][3] = 1.0;
195+
imgMsg->SetMatrix(matrix);
196+
igtl::TimeStamp::Pointer ts = igtl::TimeStamp::New();
197+
clientData.ts = ts.GetPointer();
198+
clientData.imgMsg = imgMsg.GetPointer();
199+
200+
//socket setup
201+
igtl::ServerSocket::Pointer serverSocket;
202+
serverSocket = igtl::ServerSocket::New();
203+
int r = serverSocket->CreateServer(port);
204+
205+
if (r < 0)
206+
{
207+
std::cerr << "Cannot create a server socket." << std::endl;
208+
exit(0);
209+
}
210+
std::cerr << "Created Server socket." << std::endl;
211+
212+
213+
igtl::Socket::Pointer socket;
214+
clientData.socket = socket;
215+
216+
container.SetNewRFImageCallback( &pasteIntoImage, &clientData );
217+
218+
std::cout << "StartRFReadScan" << std::endl;
219+
container.StartRFReadScan();
220+
Sleep( 100 ); // "time to start"
221+
std::cout << "StartRFmode" << std::endl;
222+
if( !hwControls.StartRFmode() )
223+
{
224+
std::cerr << "Could not start RF collection." << std::endl;
225+
return EXIT_FAILURE;
226+
}
227+
228+
if (!SetConsoleCtrlHandler(consoleHandler, TRUE))
229+
{
230+
std::cout << "Could not set control handler" << std::endl;
231+
return 1;
232+
}
233+
running = true;
234+
std::cout << "Server is running, use Ctrl-C to stop" << std::endl;
235+
while( running )
236+
{
237+
//------------------------------------------------------------
238+
// Waiting for Connection
239+
socket = serverSocket->WaitForConnection(1000);
240+
clientData.socket = socket.GetPointer();
241+
if (socket.IsNotNull()) // if client connected
242+
{
243+
Sleep(10000); //chill for a bit
244+
}
245+
246+
}
247+
248+
std::cout << "Shutting down" << std::endl;
249+
hwControls.StopAcquisition();
250+
container.StopReadScan();
251+
if (socket)
252+
{
253+
socket->CloseSocket();
254+
}
255+
256+
Sleep( 100 ); // "time to stop"
257+
return ret;
258+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<executable>
3+
<category>Ultrasound</category>
4+
<title>Interson RF OpenIGTLink Server</title>
5+
<description>Braodcast RF images over OpenIGTLink.</description>
6+
<version>0.1.0</version>
7+
<license>Apache 2.0</license>
8+
<contributor>Sam Horvath (Kitware), Matt McCormick (Kitware)</contributor>
9+
<acknowledgements>This work is funded in part by a grant with InnerOptic/Kitware</acknowledgements>
10+
<parameters>
11+
<integer>
12+
<name>port</name>
13+
<label>Port Number</label>
14+
<description>Port for OpenIGTLink Server.</description>
15+
<longflag>port</longflag>
16+
<flag>p</flag>
17+
<default>18944</default>
18+
</integer>
19+
<integer>
20+
<name>frequencyIndex</name>
21+
<label>Frequency Index</label>
22+
<description>Index of the frequency to examine. See the output of PrintIntersonProbeInfo.</description>
23+
<longflag>frequencyIndex</longflag>
24+
<flag>f</flag>
25+
<default>1</default>
26+
</integer>
27+
<integer>
28+
<name>focusIndex</name>
29+
<label>Focus Index</label>
30+
<description>Index of the focus to examine. See the output of PrintIntersonProbeInfo.</description>
31+
<longflag>focusIndex</longflag>
32+
<flag>F</flag>
33+
<default>1</default>
34+
</integer>
35+
<integer>
36+
<name>highVoltage</name>
37+
<label>High Voltage</label>
38+
<description>Percentage of the high voltage for transducer excitation.</description>
39+
<longflag>highVoltage</longflag>
40+
<flag>z</flag>
41+
<default>50</default>
42+
<minimum>0</minimum>
43+
<maximum>100</maximum>
44+
</integer>
45+
<double>
46+
<name>sos</name>
47+
<label>Speed of sound</label>
48+
<description> Assumed speed of sound in the crossed medium in mm/ms.</description>
49+
<longflag>sos</longflag>
50+
<default>1540</default>
51+
</double>
52+
</parameters>
53+
</executable>

src/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,14 @@ if( BUILD_APPLICATIONS )
9797
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:IntersonArrayCxx>" "${PROJECT_BINARY_DIR}/app/bin"
9898
)
9999
endif()
100+
101+
if( BUILD_SERVERS )
102+
add_custom_command( TARGET IntersonArrayCxx
103+
POST_BUILD
104+
COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_BINARY_DIR}/openigtlink/bin/$<CONFIG>"
105+
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${IntersonArraySDK_DIR}/Libraries/IntersonArray.dll" "${PROJECT_BINARY_DIR}/openigtlink/bin/$<CONFIG>"
106+
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:IntersonArrayCxx>" "${PROJECT_BINARY_DIR}/openigtlink/bin/$<CONFIG>"
107+
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${IntersonArraySDK_DIR}/Libraries/IntersonArray.dll" "${PROJECT_BINARY_DIR}/openigtlink/bin"
108+
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:IntersonArrayCxx>" "${PROJECT_BINARY_DIR}/openigtlink/bin"
109+
)
110+
endif()

0 commit comments

Comments
 (0)