SIRF  3.4.0
gadgetron_client.h
Go to the documentation of this file.
1 /*
2 SyneRBI Synergistic Image Reconstruction Framework (SIRF)
3 Copyright 2015 - 2019 Rutherford Appleton Laboratory STFC
4 
5 This is software developed for the Collaborative Computational
6 Project in Synergistic Reconstruction for Biomedical Imaging (formerly CCP PETMR)
7 (http://www.ccpsynerbi.ac.uk/).
8 
9 Licensed under the Apache License, Version 2.0 (the "License");
10 you may not use this file except in compliance with the License.
11 You may obtain a copy of the License at
12 http://www.apache.org/licenses/LICENSE-2.0
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18 
19 This file contains code snippets from
20 Gadgetron/apps/clients/gadgetron_ismrmrd_client/gadgetron_ismrmrd_client.cpp
21 by Michael S. Hansen
22 
23 GADGETRON SOFTWARE LICENSE V1.0, NOVEMBER 2011
24 
25 PERMISSION IS HEREBY GRANTED, FREE OF CHARGE, TO ANY PERSON OBTAINING
26 A COPY OF THIS SOFTWARE AND ASSOCIATED DOCUMENTATION FILES (THE
27 "SOFTWARE"), TO DEAL IN THE SOFTWARE WITHOUT RESTRICTION, INCLUDING
28 WITHOUT LIMITATION THE RIGHTS TO USE, COPY, MODIFY, MERGE, PUBLISH,
29 DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THE SOFTWARE, AND TO
30 PERMIT PERSONS TO WHOM THE SOFTWARE IS FURNISHED TO DO SO, SUBJECT TO
31 THE FOLLOWING CONDITIONS:
32 
33 THE ABOVE COPYRIGHT NOTICE, THIS PERMISSION NOTICE, AND THE LIMITATION
34 OF LIABILITY BELOW SHALL BE INCLUDED IN ALL COPIES OR REDISTRIBUTIONS
35 OF SUBSTANTIAL PORTIONS OF THE SOFTWARE.
36 
37 SOFTWARE IS BEING DEVELOPED IN PART AT THE NATIONAL HEART, LUNG, AND BLOOD
38 INSTITUTE, NATIONAL INSTITUTES OF HEALTH BY AN EMPLOYEE OF THE FEDERAL
39 GOVERNMENT IN THE COURSE OF HIS OFFICIAL DUTIES. PURSUANT TO TITLE 17,
40 SECTION 105 OF THE UNITED STATES CODE, THIS SOFTWARE IS NOT SUBJECT TO
41 COPYRIGHT PROTECTION AND IS IN THE PUBLIC DOMAIN. EXCEPT AS CONTAINED IN
42 THIS NOTICE, THE NAME OF THE AUTHORS, THE NATIONAL HEART, LUNG, AND BLOOD
43 INSTITUTE (NHLBI), OR THE NATIONAL INSTITUTES OF HEALTH (NIH) MAY NOT
44 BE USED TO ENDORSE OR PROMOTE PRODUCTS DERIVED FROM THIS SOFTWARE WITHOUT
45 SPECIFIC PRIOR WRITTEN PERMISSION FROM THE NHLBI OR THE NIH.THE SOFTWARE IS
46 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
47 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
48 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
50 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
51 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 */
53 
63 #ifndef GADGETRON_CLIENT
64 #define GADGETRON_CLIENT
65 
66 #ifndef WIN32_LEAN_AND_MEAN
67 #define WIN32_LEAN_AND_MEAN
68 #endif
69 
70 #include <chrono>
71 #include <condition_variable>
72 #include <exception>
73 #include <fstream>
74 #include <iomanip>
75 #include <iostream>
76 #include <map>
77 #include <memory>
78 #include <thread>
79 
80 #include <boost/asio.hpp>
81 #include <boost/thread/thread.hpp>
82 
83 #include <ismrmrd/dataset.h>
84 #include <ismrmrd/ismrmrd.h>
85 #include <ismrmrd/meta.h>
86 
87 #include "sirf/Gadgetron/cgadgetron_shared_ptr.h"
89 
90 enum GadgetronMessageID {
91  GADGET_MESSAGE_INT_ID_MIN = 0,
92  GADGET_MESSAGE_CONFIG_FILE = 1,
93  GADGET_MESSAGE_CONFIG_SCRIPT = 2,
94  GADGET_MESSAGE_PARAMETER_SCRIPT = 3,
95  GADGET_MESSAGE_CLOSE = 4,
96  GADGET_MESSAGE_TEXT = 5,
97  GADGET_MESSAGE_INT_ID_MAX = 999,
98  GADGET_MESSAGE_EXT_ID_MIN = 1000,
99  GADGET_MESSAGE_ISMRMRD_ACQUISITION = 1008,
100  GADGET_MESSAGE_CLOUD_JOB = 1013,
101  GADGET_MESSAGE_GADGETCLOUD_JOB = 1014,
102  GADGET_MESSAGE_DICOM_WITHNAME = 1018,
103  GADGET_MESSAGE_DEPENDENCY_QUERY = 1019,
104  GADGET_MESSAGE_ISMRMRD_IMAGE = 1022,
105  GADGET_MESSAGE_RECONDATA = 1023,
106  GADGET_MESSAGE_EXT_ID_MAX = 4096
107 };
108 
109 #define MAX_BLOBS_LOG_10 6
110 
111 namespace sirf {
112 
114  uint16_t id;
115  };
116 
118  char configuration_file[1024];
119  };
120 
122  uint32_t script_length;
123  };
124 
125  class GadgetronClientException : public std::exception {
126  public:
127  GadgetronClientException(std::string msg) : msg_(msg) {}
128  virtual ~GadgetronClientException() throw() {}
129  virtual const char* what() const throw()
130  {
131  return msg_.c_str();
132  }
133  protected:
134  std::string msg_;
135  };
136 
141  public:
142  virtual ~GadgetronClientMessageReader() {}
146  virtual void read(boost::asio::ip::tcp::socket* s) = 0;
147  };
148 
154  public:
156  (gadgetron::shared_ptr<MRAcquisitionData> ptr_acqs) : ptr_acqs_(ptr_acqs) {}
158 
159  virtual void read(boost::asio::ip::tcp::socket* stream);
160 
161  private:
162  gadgetron::shared_ptr<MRAcquisitionData> ptr_acqs_;
163  };
164 
170  public:
172  (gadgetron::shared_ptr<GadgetronImageData> ptr_images) : ptr_images_(ptr_images) {}
174 
175  template <typename T>
176  void read_data_attributes
177  (ISMRMRD::Image<T>* ptr, const ISMRMRD::ImageHeader& h, void** ptr_ptr,
178  boost::asio::ip::tcp::socket* stream)
179  {
180  ISMRMRD::Image < T >* ptr_im = new ISMRMRD::Image < T > ;
181  *ptr_ptr = (void*)ptr_im;
182  ISMRMRD::Image<T>& im = *ptr_im;
183  im.setHead(h);
184  //im.setImageType(ISMRMRD::ISMRMRD_IMTYPE_MAGNITUDE);
185 
186  //Read meta attributes
187  typedef unsigned long long size_t_type;
188  size_t_type meta_attrib_length;
189  boost::asio::read
190  (*stream, boost::asio::buffer(&meta_attrib_length, sizeof(size_t_type)));
191  if (meta_attrib_length > 0) {
192  std::string meta_attrib(meta_attrib_length, 0);
193  boost::asio::read(*stream, boost::asio::buffer(const_cast < char* >
194  (meta_attrib.c_str()), meta_attrib_length));
195  im.setAttributeString(meta_attrib);
196  }
197  //Read image data
198  boost::asio::read
199  (*stream, boost::asio::buffer(im.getDataPtr(), im.getDataSize()));
200  }
201 
202  virtual void read(boost::asio::ip::tcp::socket* stream);
203 
204  private:
205  gadgetron::shared_ptr<GadgetronImageData> ptr_images_;
206  };
207 
210  public:
211  GadgetronClientBlobMessageReader(std::string fileprefix, std::string filesuffix)
212  : number_of_calls_(0)
213  , file_prefix(fileprefix)
214  , file_suffix(filesuffix)
215  {
216  }
217 
219 
220  virtual void read(boost::asio::ip::tcp::socket* socket)
221  {
222  // MUST READ 32-bits
223  uint32_t nbytes;
224  boost::asio::read(*socket, boost::asio::buffer(&nbytes, sizeof(uint32_t)));
225 
226  std::vector<char> data(nbytes, 0);
227  boost::asio::read(*socket, boost::asio::buffer(&data[0], nbytes));
228 
229  unsigned long long fileNameLen;
230  boost::asio::read(*socket, boost::asio::buffer(&fileNameLen, sizeof(unsigned long long)));
231 
232  std::string filenameBuf(fileNameLen, 0);
233  boost::asio::read(*socket, boost::asio::buffer(const_cast<char*>
234  (filenameBuf.c_str()), fileNameLen));
235 
236  typedef unsigned long long size_t_type;
237 
238  size_t_type meta_attrib_length;
239  boost::asio::read(*socket, boost::asio::buffer(&meta_attrib_length, sizeof(size_t_type)));
240 
241  std::string meta_attrib;
242  if (meta_attrib_length > 0) {
243  std::string meta_attrib_socket(meta_attrib_length, 0);
244  boost::asio::read(*socket, boost::asio::buffer(const_cast<char*>(meta_attrib_socket.c_str()), meta_attrib_length));
245  meta_attrib = meta_attrib_socket;
246  }
247 
248  std::stringstream filename;
249  std::string filename_attrib;
250 
251  // Create the filename: (prefix_%06.suffix)
252  filename << file_prefix << "_";
253  filename << std::setfill('0') << std::setw(MAX_BLOBS_LOG_10) << number_of_calls_;
254  filename_attrib = filename.str();
255  filename << "." << file_suffix;
256  filename_attrib.append("_attrib.xml");
257 
258  std::cout << "Writing image " << filename.str() << std::endl;
259 
260  std::ofstream outfile;
261  outfile.open(filename.str().c_str(), std::ios::out | std::ios::binary);
262 
263  std::ofstream outfile_attrib;
264  if (meta_attrib_length > 0) {
265  outfile_attrib.open(filename_attrib.c_str(), std::ios::out | std::ios::binary);
266  }
267 
268  if (outfile.good()) {
269  /* write 'size' bytes starting at 'data's pointer */
270  outfile.write(&data[0], nbytes);
271  outfile.close();
272  if (meta_attrib_length > 0) {
273  outfile_attrib.write(meta_attrib.c_str(), meta_attrib.length());
274  outfile_attrib.close();
275  }
276  number_of_calls_++;
277  }
278  else {
279  throw GadgetronClientException("Unable to write blob to output file\n");
280  }
281  }
282 
283  protected:
284  size_t number_of_calls_;
285  std::string file_prefix;
286  std::string file_suffix;
287  };
288 
293  public:
294  GadgetronClientConnector() : socket_(0), timeout_ms_(2000)
295  {}
296  virtual ~GadgetronClientConnector()
297  {
298  if (socket_) {
299  socket_->close();
300  delete socket_;
301  }
302  }
303 
304  void set_timeout(unsigned int t)
305  {
306  timeout_ms_ = t;
307  }
308 
309  void read_task();
310 
311  void wait()
312  {
313  reader_thread_.join();
314  }
315 
316  void connect(std::string hostname, std::string port);
317 
318  void send_gadgetron_close();
319 
320  void send_gadgetron_configuration_file(std::string config_xml_name);
321 
322  void send_gadgetron_configuration_script(std::string xml_string);
323 
324  void send_gadgetron_parameters(std::string xml_string);
325 
326  void send_ismrmrd_acquisition(ISMRMRD::Acquisition& acq);
327 
328  template<typename T>
329  void send_ismrmrd_image(ISMRMRD::Image<T>* ptr_im)
330  {
331  ISMRMRD::Image<T>& im = *ptr_im;
332  if (!socket_)
333  throw GadgetronClientException("Invalid socket.");
334 
336  id.id = GADGET_MESSAGE_ISMRMRD_IMAGE;
337 
338  boost::asio::write
339  (*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier)));
340  boost::asio::write
341  (*socket_,
342  boost::asio::buffer(&im.getHead(), sizeof(ISMRMRD::ImageHeader)));
343 
344  size_t meta_attrib_length = im.getAttributeStringLength();
345  std::string meta_attrib(meta_attrib_length + 1, 0);
346  im.getAttributeString(meta_attrib);
347 
348  boost::asio::write
349  (*socket_, boost::asio::buffer(&meta_attrib_length, sizeof(size_t)));
350  boost::asio::write
351  (*socket_, boost::asio::buffer(meta_attrib.c_str(), meta_attrib_length));
352 
353  boost::asio::write
354  (*socket_, boost::asio::buffer(im.getDataPtr(), im.getDataSize()));
355  }
356 
357  void send_wrapped_image(const ImageWrap& iw)
358  {
359  IMAGE_PROCESSING_SWITCH(iw.type(), send_ismrmrd_image, iw.ptr_image());
360  }
361 
362  void register_reader
363  (unsigned short slot, gadgetron::shared_ptr<GadgetronClientMessageReader> r)
364  {
365  readers_[slot] = r;
366  }
367 
368  protected:
369  typedef
370  std::map < unsigned short, gadgetron::shared_ptr<GadgetronClientMessageReader> >
371  maptype;
372 
373  GadgetronClientMessageReader* find_reader(unsigned short r);
374 
375  boost::asio::io_service io_service;
376  boost::asio::ip::tcp::socket* socket_;
377  boost::thread reader_thread_;
378  maptype readers_;
379  unsigned int timeout_ms_;
380  };
381 
382 }
383 
384 #endif
Abstract base class for receiving messages from Gadgetron server.
Definition: gadgetron_client.h:140
Class for accumulating acquisitions sent by Gadgetron server.
Definition: gadgetron_client.h:152
Class for accumulating ISMRMRD images sent by Gadgetron server.
Definition: gadgetron_client.h:168
Definition: gadgetron_client.h:121
virtual void read(boost::asio::ip::tcp::socket *socket)
Definition: gadgetron_client.h:220
Definition: gadgetron_client.h:208
Abstract data container.
Definition: GeometricalInfo.cpp:141
Specification file for data container classes for Gadgetron data.
Definition: gadgetron_client.h:125
Class for communicating with Gadgetron server.
Definition: gadgetron_client.h:292
Definition: gadgetron_client.h:117
Definition: gadgetron_client.h:113
Wrapper for ISMRMRD::Image.
Definition: gadgetron_image_wrap.h:106