PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusClariusOEM.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2  Program: Plus
3  Copyright (c) Verdure Imaging Inc, Stockton, California. All rights reserved.
4  See License.txt for details.
5 
6  We would like to acknowledge Verdure Imaging Inc for generously open-sourcing
7  this support for the Clarius OEM interface to the PLUS & Slicer communities.
8 =========================================================Plus=header=end*/
9 
10 // Local includes
11 #include "PlusConfigure.h"
12 #include "vtkPlusChannel.h"
13 #include "vtkPlusClariusOEM.h"
14 #include "PixelCodec.h"
15 #include "vtkPlusDataSource.h"
17 
18 // Wifi & BLE helpers
19 #include "ClariusBLE.h"
20 #include "ClariusWifi.h"
21 
22 // Clarius Includes
23 #include <solum.h>
24 #include <solum_def.h>
25 
26 // VTK includes
27 #include <vtkImageData.h>
28 #include <vtkInformation.h>
29 #include <vtkMatrix4x4.h>
30 #include <vtkNew.h>
31 #include <vtkSmartPointer.h>
32 
33 // STL includes
34 #include <algorithm>
35 #include <cctype>
36 #include <chrono>
37 #include <future>
38 #include <map>
39 #include <sstream>
40 #include <string>
41 
42 // Clarius enable / disable values
43 #define CLARIUS_TRUE 1
44 #define CLARIUS_FALSE 0
45 #define CLARIUS_RUN 1
46 #define CLARIUS_STOP 0
47 
48 // Clarius connection state values
49 #define CLARIUS_STATE_NOT_INITIALIZED -1
50 #define CLARIUS_STATE_NOT_CONNECTED 0
51 #define CLARIUS_STATE_CONNECTED 1
52 
53 const std::string vtkPlusClariusOEM::OVERLAY_PORT_NAME = "Overlay";
54 
55 //-------------------------------------------------------------------------------------------------
56 // instance memory
57 vtkPlusClariusOEM* vtkPlusClariusOEM::instance;
58 
59 //-------------------------------------------------------------------------------------------------
60 // free helper functions
61 //-------------------------------------------------------------------------------------------------
62 std::string to_string(ClariusAvailability avail)
63 {
64  switch (avail)
65  {
67  return "Available";
69  return "Listen";
71  return "Not Available";
72  default:
73  return "Unknown ClariusAvailability";
74  }
75 }
76 
77 //-------------------------------------------------------------------------------------------------
79 {
80  switch (mode)
81  {
83  return "Access Point";
85  return "Local Area Network";
86  default:
87  return "Unknown ClariusWifiMode";
88  }
89 }
90 
91 //-------------------------------------------------------------------------------------------------
92 namespace
93 {
94  enum class BUTTON_MODE
95  {
96  DISABLED = CusButtonSetting::ButtonDisabled,
97  FREEZE = CusButtonSetting::ButtonFreeze,
98  USER = CusButtonSetting::ButtonUser
99  };
100 
101  static std::map<BUTTON_MODE, std::string> ButtonModeEnumToString{
102  {BUTTON_MODE::FREEZE, "FREEZE"},
103  {BUTTON_MODE::USER, "USER"},
104  {BUTTON_MODE::DISABLED, "DISABLED"}
105  };
106 
107  static std::map<int, std::string> ImagingModeStrings{
108  {CusMode::BMode, "BMode"},
109  {CusMode::Compounding, "Compounding"},
110  {CusMode::MMode, "MMode"},
111  {CusMode::ColorMode, "ColorMode"},
112  {CusMode::PowerMode, "PowerMode"},
113  {CusMode::PwMode, "PwMode"},
114  {CusMode::NeedleEnhance, "NeedleEnhance"},
115  {CusMode::Strain, "Strain"},
116  {CusMode::RfMode, "RfMode"},
117  };
118 
119  static const double CM_TO_MM = 10.0;
120  static const double MM_TO_CM = 0.1;
121  static const double UM_TO_MM = 0.001;
122 
123  static const int CLARIUS_SHORT_DELAY_MS = 10;
124  static const int CLARIUS_LONG_DELAY_MS = 1000;
125 
126  static const std::string BATTERY_FIELD_TAG = "ClariusBattery";
127  static const std::string TEMP_FIELD_TAG = "ClariusTemp";
128  static const std::string FRAME_RATE_FIELD_TAG = "ClariusFrameRate";
129  static const std::string BUTTON_FIELD_TAG = "ClariusButton";
130  static const std::string UP_BUTTON_TAG = "Up";
131  static const std::string DOWN_BUTTON_TAG = "Down";
132  static const std::string NO_BUTTON_TAG = "None";
133  static const std::string NUM_CLICKS_FIELD_TAG = "ClariusNumClicks";
134  static const int SEND_BUTTON_STATE_FOR_N_FRAMES = 20;
135 
136  static const FrameSizeType DEFAULT_FRAME_SIZE = { 512, 512, 1 };
137 
138  static const bool DEFAULT_ENABLE_AUTO_GAIN = false;
139 
140  static const bool DEFAULT_ENABLE_5V_RAIL = false;
141 
142  static const bool DEFAULT_FREEZE_ON_POOR_WIFI_SIGNAL = true;
143 
144  static const bool DEFAULT_KEEP_AWAKE_CHARGING = true;
145 
146  static const bool DEFAULT_POWER_BUTTONS_ENABLED = true;
147 
148  static const bool DEFAULT_SOUND_ENABLED = true;
149 
150  static const int DEFAULT_STATIONARY_TIMEOUT_SEC = 0;
151 
152  static const bool DEFAULT_WAKE_ON_SHAKE = false;
153 
154  static const bool DEFAULT_FORCE_LOG_SEND = false;
155 
156  static const bool DEFAULT_PENETRATION_MODE_ENABLED = false;
157 
158  static const int DEFAULT_CONTACT_DETECTION_TIMEOUT_SEC = 15;
159 
160  static const int DEFAULT_AUTO_FREEZE_TIMEOUT_SEC = 60;
161 
162  static const int DEFAULT_KEEP_AWAKE_TIMEOUT_SEC = 60;
163 
164  static const int DEFAULT_DEEP_SLEEP_TIMEOUT_HR = 0;
165 
166  static const BUTTON_MODE DEFAULT_UP_BUTTON_MODE = BUTTON_MODE::DISABLED;
167 
168  static const BUTTON_MODE DEFAULT_DOWN_BUTTON_MODE = BUTTON_MODE::FREEZE;
169 
170  static const double DEFAULT_DEPTH_MM = 100.0;
171 
172  static const double DEFAULT_GAIN_PERCENT = 80.0;
173 
174  static const double DEFAULT_DYNRANGE_PERCENT = 80.0;
175 
176  static const std::vector<double> DEFAULT_TGC_DB = { 5, 5, 5 };
177 
178  static const bool DEFAULT_ENABLE_AUTO_FOCUS = false;
179 
180  static std::map<int, std::string> ConnectEnumToString{
181  {CusConnection::ProbeConnected, "CONNECT_SUCCESS"},
182  {CusConnection::ProbeDisconnected, "CONNECT_DISCONNECT"},
183  {CusConnection::ConnectionFailed, "CONNECT_FAILED"},
184  {CusConnection::SwUpdateRequired, "CONNECT_SWUPDATE"},
185  {CusConnection::ConnectionError, "CONNECT_ERROR"},
186  };
187 
188  static const std::string TRANSD_PORT_NAME = "Transd";
189 }
190 
191 //-------------------------------------------------------------------------------------------------
192 // vtkInternal
193 //-------------------------------------------------------------------------------------------------
194 
195 class vtkPlusClariusOEM::vtkInternal
196 {
197 public:
198 
199  vtkInternal(vtkPlusClariusOEM* ext);
200 
201  virtual ~vtkInternal()
202  {
203  }
204 
205 protected:
206 
207  friend class vtkPlusClariusOEM;
208 
209  // Clarius callbacks
210  static void ListFn(const char* list, int sz);
211 
212  static void ConnectFn(CusConnection ret, int port, const char* status);
213 
214  static void CertFn(int daysValid);
215 
216  static void PowerDownFn(CusPowerDown ret, int tm);
217 
218  static void SwUpdateFn(CusSwUpdate ret);
219 
220  static void RawImageFn(const void* newImage, const CusRawImageInfo* nfo, int npos, const CusPosInfo* pos);
221 
222  static void ProcessedImageFn(const void* newImage, const CusProcessedImageInfo* nfo, int npos, const CusPosInfo* pos);
223 
224  static void SpectralImageFn(const void* newImage, const CusSpectralImageInfo* nfo);
225 
226  static void ImuDataFn(const CusPosInfo* pos);
227 
228  static void ImagingFn(CusImagingState ready, int imaging);
229 
230  static void ButtonFn(CusButton btn, int clicks);
231 
232  static void ProgressFn(int progress);
233 
234  static void ErrorFn(CusErrorCode errorCode, const char* msg);
235 
236  std::string ImagingModeToString(int mode)
237  {
238  if (ImagingModeStrings.find(mode) != ImagingModeStrings.end())
239  {
240  return ImagingModeStrings[mode];
241  }
242  else
243  {
244  return "Unknown Imaging Mode";
245  }
246  }
247 
248  // log user settings to console
249  void LogUserSettings();
250 
251  //
252  // members
253  //
254 
255  // user configurable params
256  std::string ProbeSerialNum;
257  std::string PathToCert;
258  FrameSizeType FrameSize;
259  std::string ProbeType;
260  std::string ImagingApplication;
261  bool EnableAutoGain;
262  bool Enable5v;
263  bool FreezeOnPoorWifiSignal;
264  bool KeepAwakeCharging;
265  bool PowerButtonsEnabled;
266  bool SoundEnabled;
267  int StationaryTimeoutSec;
268  bool WakeOnShake;
269  bool ForceLogSend;
270  bool EnablePenetrationMode;
271  int ContactDetectionTimeoutSec;
272  int AutoFreezeTimeoutSec;
273  int KeepAwakeTimeoutMin;
274  int DeepSleepTimeoutHr;
275  BUTTON_MODE UpButtonMode;
276  BUTTON_MODE DownButtonMode;
277  int ImagingMode;
278 
279  // parameters retrieved from the probe over BLE
280  std::string Ssid;
281  std::string Password;
282  std::string IpAddress;
283  int TcpPort;
284 
285  // parameters retrieved from the probe using the OEM API
286  std::promise<std::vector<std::string>> PromiseProbes;
287  std::promise<std::vector<std::string>> PromiseApplications;
288  std::promise<void> ConnectionBarrier;
289 
290  // pointers to DataSources
291  std::vector<vtkPlusDataSource*> BModeSources;
292  std::vector<vtkPlusDataSource*> OverlaySources;
293  vtkPlusDataSource* TransdSource;
294 
295  // button press info
296  std::string PressedButton;
297  int ButtonNumClicks;
298  int ButtonSentCount; // button state is sent for SEND_BUTTON_STATE_FOR_N_FRAMES
299  // frames after button is clicked to ensure user can process
300  // it in Slicer even if a frame is skipped
301 
302  CusStatusInfo CurrentStatus;
303 
304  bool EnableAutoFocus;
305 
306  enum class EXPECTED_LIST
307  {
308  PROBES,
309  APPLICATIONS,
310  UNKNOWN
311  } ExpectedList;
312 
313 private:
314  vtkPlusClariusOEM* External;
315 
316  // BLE interface
317  ClariusBLE BleHelper;
318 
319  // Wifi helper class
320  ClariusWifi WifiHelper;
321 };
322 
323 //-------------------------------------------------------------------------------------------------
324 vtkPlusClariusOEM::vtkInternal::vtkInternal(vtkPlusClariusOEM* ext)
325  : External(ext)
326  , ProbeSerialNum("")
327  , PathToCert("")
328  , FrameSize(DEFAULT_FRAME_SIZE)
329  , ProbeType("")
330  , ImagingApplication("")
331  , EnableAutoGain(DEFAULT_ENABLE_AUTO_GAIN)
332  , Enable5v(DEFAULT_ENABLE_5V_RAIL)
333  , FreezeOnPoorWifiSignal(DEFAULT_FREEZE_ON_POOR_WIFI_SIGNAL)
334  , KeepAwakeCharging(DEFAULT_KEEP_AWAKE_CHARGING)
335  , PowerButtonsEnabled(DEFAULT_POWER_BUTTONS_ENABLED)
336  , SoundEnabled(DEFAULT_SOUND_ENABLED)
337  , StationaryTimeoutSec(DEFAULT_STATIONARY_TIMEOUT_SEC)
338  , WakeOnShake(DEFAULT_WAKE_ON_SHAKE)
339  , ForceLogSend(DEFAULT_FORCE_LOG_SEND)
340  , EnablePenetrationMode(DEFAULT_PENETRATION_MODE_ENABLED)
341  , ContactDetectionTimeoutSec(DEFAULT_CONTACT_DETECTION_TIMEOUT_SEC)
342  , AutoFreezeTimeoutSec(DEFAULT_AUTO_FREEZE_TIMEOUT_SEC)
343  , KeepAwakeTimeoutMin(DEFAULT_KEEP_AWAKE_TIMEOUT_SEC)
344  , DeepSleepTimeoutHr(DEFAULT_DEEP_SLEEP_TIMEOUT_HR)
345  , UpButtonMode(DEFAULT_UP_BUTTON_MODE)
346  , DownButtonMode(DEFAULT_DOWN_BUTTON_MODE)
347  , ImagingMode(CusMode::BMode)
348  , IpAddress("")
349  , TcpPort(-1)
350  , TransdSource(nullptr)
351  , PressedButton(NO_BUTTON_TAG)
352  , ButtonNumClicks(0)
353  , ButtonSentCount(0)
354  , EnableAutoFocus(DEFAULT_ENABLE_AUTO_FOCUS)
355 {
356 }
357 
358 //-------------------------------------------------------------------------------------------------
359 void vtkPlusClariusOEM::vtkInternal::ListFn(const char* list, int sz)
360 {
362 
363  std::vector<std::string> vec;
364 
365  std::stringstream ss(list);
366  while (ss.good())
367  {
368  std::string substr;
369  getline(ss, substr, ',');
370  vec.push_back(substr);
371  }
372 
373  if (device->Internal->ExpectedList == EXPECTED_LIST::PROBES)
374  {
375  device->Internal->PromiseProbes.set_value(vec);
376  }
377  else if (device->Internal->ExpectedList == EXPECTED_LIST::APPLICATIONS)
378  {
379  device->Internal->PromiseApplications.set_value(vec);
380  }
381 }
382 
383 //-------------------------------------------------------------------------------------------------
384 void vtkPlusClariusOEM::vtkInternal::ConnectFn(CusConnection ret, int port, const char* status)
385 {
387 
388  switch (ret)
389  {
390  case ConnectionError:
391  LOG_ERROR("Connection status: error - " << status);
392  device->Disconnect();
393  break;
394  case ProbeConnected:
395  LOG_INFO("Connection status: probe connected - " << status);
396  break;
397  case ProbeDisconnected:
398  LOG_INFO("Connection status: probe disconnected - " << status);
399  device->Disconnect();
400  break;
401  case ConnectionFailed:
402  LOG_ERROR("Connection status: connection failed - " << status);
403  device->Disconnect();
404  break;
405  case SwUpdateRequired:
406  LOG_INFO("Connection status: software update required - " << status);
407  device->Disconnect();
408  break;
409  }
410 
411  if (ret == CusConnection::ProbeConnected)
412  {
413  // connection succeeded, set Internal->Connected variable to end busy wait in InternalConnect
414  device->Internal->ConnectionBarrier.set_value();
415  }
416 }
417 
418 //-------------------------------------------------------------------------------------------------
419 void vtkPlusClariusOEM::vtkInternal::CertFn(int daysValid)
420 {
421  if (daysValid <= 0)
422  {
423  LOG_ERROR("Invalid or expired certificate provided for Clarius OEM device");
424  }
425  else
426  {
427  LOG_INFO("Clarius certificate is valid for " << daysValid << " more days");
428  }
429 }
430 
431 //-------------------------------------------------------------------------------------------------
432 void vtkPlusClariusOEM::vtkInternal::PowerDownFn(CusPowerDown ret, int tm)
433 {
434  std::stringstream ss;
435  ss << "Clarius probe will power down ";
436 
437  if (tm == 0)
438  {
439  ss << "immediately as a result of ";
440  }
441  else
442  {
443  ss << "in " << tm << " seconds as a result of ";
444  }
445 
446  if (ret == CusPowerDown::Idle)
447  {
448  ss << "being idle for an extended period of time. ";
449  }
450  else if (ret == CusPowerDown::TooHot)
451  {
452  ss << "overheating. ";
453  }
454  else if (ret == CusPowerDown::LowBattery)
455  {
456  ss << "running out of battery. ";
457  }
458  else if (ret == CusPowerDown::ButtonOff)
459  {
460  ss << "user holding the shutdown button. ";
461  }
462  else
463  {
464  ss << "an unspecified reason. ";
465  }
466 
467  ss << "If Clarius probe has powered off please turn it back on and restart PLUS, if desired.";
468  LOG_ERROR(ss.str());
469 }
470 
471 //-------------------------------------------------------------------------------------------------
472 void vtkPlusClariusOEM::vtkInternal::SwUpdateFn(CusSwUpdate ret)
473 {
474  LOG_ERROR("Clarius SwUpdateFn callback was called, but this feature is not supported by PLUS. Please update using the Clarius iOS/Android App");
475 }
476 
477 //-------------------------------------------------------------------------------------------------
478 void vtkPlusClariusOEM::vtkInternal::RawImageFn(const void* newImage, const CusRawImageInfo* nfo, int npos, const CusPosInfo* pos)
479 {
480  LOG_ERROR("Support for Clarius OEM raw images has not been implemented. If you desire this feature please submit an issue to request it on the PlusToolkit/PlusLib GitHub repository");
481 }
482 
483 //-------------------------------------------------------------------------------------------------
484 void vtkPlusClariusOEM::vtkInternal::SpectralImageFn(const void* newImage, const CusSpectralImageInfo* nfo)
485 {
486  LOG_ERROR("Support for Clarius OEM spectral images has not been implemented. If you desire this feature please submit an issue to request it on the PlusToolkit/PlusLib GitHub repository");
487 }
488 
489 //-------------------------------------------------------------------------------------------------
490 void vtkPlusClariusOEM::vtkInternal::ImuDataFn(const CusPosInfo* pos)
491 {
492  LOG_ERROR("Support for Clarius OEM IMU data has not been implemented. If you desire this feature please submit an issue to request it on the PlusToolkit/PlusLib GitHub repository");
493 }
494 
495 //-------------------------------------------------------------------------------------------------
497 {
498  if (this->UpdateProbeStatus() != PLUS_SUCCESS)
499  {
500  LOG_ERROR("Failed to update probe status");
501  }
502  return PLUS_SUCCESS;
503 }
504 
505 //-------------------------------------------------------------------------------------------------
507 {
508  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
509  {
510  return PLUS_SUCCESS;
511  }
512 
513  if (solumStatusInfo(&this->Internal->CurrentStatus) != 0)
514  {
515  LOG_ERROR("Failed to retrieve solumStatusInfo");
516  return PLUS_FAIL;
517  }
518  return PLUS_SUCCESS;
519 }
520 
521 //-------------------------------------------------------------------------------------------------
522 void vtkPlusClariusOEM::vtkInternal::ProcessedImageFn(const void* oemImage, const CusProcessedImageInfo* nfo, int npos, const CusPosInfo* pos)
523 {
525  if (device == NULL)
526  {
527  LOG_ERROR("vtkPlusClariusOEM::vtkInternal::ProcessedImageFn called when Clarius instance was NULL!");
528  return;
529  }
530 
531  // check if still connected
532  if (!device->Connected)
533  {
534  return;
535  }
536 
537  if (oemImage == NULL)
538  {
539  LOG_ERROR("NULL frame received by the Clarius OEM device");
540  return;
541  }
542 
543  // check if source is valid, if not - nothing to do
544  if (!nfo->overlay && device->Internal->BModeSources.size() == 0)
545  {
546  return;
547  }
548  else if (nfo->overlay && device->Internal->OverlaySources.size() == 0)
549  {
550  return;
551  }
552 
553  // setup source
554  const double unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
555 
556  vtkSmartPointer<vtkImageData> vtkImage = vtkSmartPointer<vtkImageData>::New();
557  vtkNew<vtkInformation> info;
558  vtkImage->SetExtent(0, nfo->width - 1, 0, nfo->height - 1, 0, 1);
559  vtkImage->SetOrigin(0.0, 0.0, 0.0);
560  vtkImage->SetSpacing(1.0, 1.0, 1.0);
561 
562  std::vector<vtkPlusDataSource*> dataSources = device->Internal->BModeSources;
563  if (nfo->overlay)
564  {
565  dataSources = device->Internal->OverlaySources;
566  }
567 
568  for (auto dataSource : dataSources)
569  {
570  if (dataSource->GetImageType() == US_IMG_RGB_COLOR)
571  {
572  vtkImage->AllocateScalars(VTK_UNSIGNED_CHAR, 3);
574  nfo->width,
575  nfo->height,
576  (unsigned char*)oemImage,
577  (unsigned char*)vtkImage->GetScalarPointer()
578  );
579  }
580  else
581  {
582  // convert Clarius RGBA to grayscale
583  // format is:
584  // B = ultrasound value
585  // G = ultrasound value
586  // R = ultrasound value
587  // A = 255
588  vtkImage->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
591  nfo->width,
592  nfo->height,
593  (unsigned char*)oemImage,
594  (unsigned char*)vtkImage->GetScalarPointer()
595  );
596  }
597  }
598 
599 
600  // custom fields (battery & button clicks)
601  igsioFieldMapType customFields;
602  customFields[BATTERY_FIELD_TAG].first = FRAMEFIELD_FORCE_SERVER_SEND;
603  customFields[BATTERY_FIELD_TAG].second = std::to_string(device->Internal->CurrentStatus.battery);
604  customFields[TEMP_FIELD_TAG].first = FRAMEFIELD_FORCE_SERVER_SEND;
605  customFields[TEMP_FIELD_TAG].second = std::to_string(device->Internal->CurrentStatus.temperature);
606  customFields[FRAME_RATE_FIELD_TAG].first = FRAMEFIELD_FORCE_SERVER_SEND;
607  customFields[FRAME_RATE_FIELD_TAG].second = std::to_string(device->Internal->CurrentStatus.frameRate);
608 
609  customFields[BUTTON_FIELD_TAG].first = FRAMEFIELD_FORCE_SERVER_SEND;
610  customFields[BUTTON_FIELD_TAG].second = device->Internal->PressedButton;
611  customFields[NUM_CLICKS_FIELD_TAG].first = FRAMEFIELD_FORCE_SERVER_SEND;
612  customFields[NUM_CLICKS_FIELD_TAG].second = std::to_string(device->Internal->ButtonNumClicks);
613 
614  // reset button state if sent SEND_BUTTON_STATE_FOR_N_FRAMES times
615  if (device->Internal->ButtonSentCount > 0)
616  {
617  --device->Internal->ButtonSentCount;
618  }
619  else
620  {
621  device->Internal->PressedButton = NO_BUTTON_TAG;
622  device->Internal->ButtonNumClicks = 0;
623  }
624 
625  // update the image
626  for (auto dataSource : dataSources)
627  {
628  dataSource->AddItem(
629  vtkImage->GetScalarPointer(),
630  dataSource->GetInputImageOrientation(),
631  dataSource->GetInputFrameSize(),
632  VTK_UNSIGNED_CHAR,
633  dataSource->GetImageType() == US_IMG_RGB_COLOR ? 3 : 1,
634  dataSource->GetImageType(),
635  0,
636  device->FrameNumber,
637  unfilteredTimestamp,
638  unfilteredTimestamp,
639  &customFields
640  );
641  }
642 
643  // if transd source is valid, update the ImageToTransd (or similarly named)
644  // transform which localizes the image to the center of the transducer
645  // and correctly sizes the image
646  if (device->Internal->TransdSource)
647  {
648  int i = nfo->width / 2;
649  double transd[2] = { static_cast<double>(i), 0.0 };
650  for (int j = 0; j < nfo->height; j++)
651  {
652  unsigned char imval = vtkImage->GetScalarComponentAsDouble(i, j, 0, 0);
653  if (imval != 0)
654  {
655  transd[0] = i;
656  transd[1] = j;
657  break;
658  }
659  }
660 
661  vtkSmartPointer<vtkMatrix4x4> tsfm = vtkSmartPointer<vtkMatrix4x4>::New();
662  tsfm->Identity();
663  double mmPerPixel = nfo->micronsPerPixel * UM_TO_MM;
664  tsfm->SetElement(0, 0, mmPerPixel);
665  tsfm->SetElement(1, 1, mmPerPixel);
666  tsfm->SetElement(2, 2, mmPerPixel);
667  tsfm->SetElement(0, 3, -transd[0] * mmPerPixel);
668  tsfm->SetElement(1, 3, -transd[1] * mmPerPixel);
669  device->Internal->TransdSource->AddTimeStampedItem(tsfm, TOOL_OK, device->FrameNumber, unfilteredTimestamp, unfilteredTimestamp, &customFields);
670  }
671 
672  device->FrameNumber++;
673 }
674 
675 //-------------------------------------------------------------------------------------------------
676 void vtkPlusClariusOEM::vtkInternal::ImagingFn(CusImagingState ready, int imaging)
677 {
678  if (ready == CusImagingState::ImagingNotReady)
679  {
680  LOG_WARNING("Clarius imaging is not ready yet...");
681  }
682  else if (ready == CusImagingState::ImagingReady)
683  {
684  LOG_INFO("Clarius imaging is " << (imaging ? "running" : "stopped"));
685  }
686  else if (ready == CusImagingState::CertExpired)
687  {
688  LOG_ERROR("Clarius certificate needs to be updated prior to imaging");
689  }
690  else if (ready == CusImagingState::PoorWifi)
691  {
692  LOG_WARNING("Clarius imaging stopped as a result of a poor Wi-Fi connection");
693  }
694  else if (ready == CusImagingState::NoContact)
695  {
696  LOG_INFO("Clarius imaging stopped as a result of no patient contact for specified timeout duration");
697  }
698  else if (ready == CusImagingState::ChargingChanged)
699  {
700  LOG_WARNING("Clarius imaging " << (imaging ? "started" : "stopped") << " due to a change in charging status");
701  }
702  else if (ready == CusImagingState::LowBandwidth)
703  {
704  LOG_INFO("Clarius low bandwidth was detected, imaging parameters were adjusted");
705  }
706  else if (ready == CusImagingState::MotionSensor)
707  {
708  LOG_INFO("Clarius imaging " << (imaging ? "started" : "stopped") << " due to change in motion sensor");
709  }
710  else
711  {
712  LOG_ERROR("Clarius ImagingFn called with unknown 'ready' state");
713  }
714 }
715 
716 //-------------------------------------------------------------------------------------------------
720 void vtkPlusClariusOEM::vtkInternal::ButtonFn(CusButton btn, int clicks)
721 {
723  if (device == NULL)
724  {
725  LOG_ERROR("vtkPlusClariusOEM::vtkInternal::ButtonFn called when Clarius instance was NULL!");
726  return;
727  }
728 
729  // check if still connected
730  if (!device->Connected)
731  {
732  LOG_ERROR("ClariusOEM device unexpectedly disconnected from Clarius Device. IpAddress = " << device->Internal->IpAddress
733  << " Port = " << device->Internal->TcpPort);
734  return;
735  }
736 
737  // set button state
738  device->Internal->ButtonNumClicks = clicks;
739  if (btn == CusButton::ButtonDown)
740  {
741  device->Internal->PressedButton = DOWN_BUTTON_TAG;
742  }
743  else if (btn == CusButton::ButtonUp)
744  {
745  device->Internal->PressedButton = UP_BUTTON_TAG;
746  }
747  else
748  {
749  LOG_WARNING("Unexpected Clarius button value of " << btn << " received in vtkPlusClariusOEM::vtkInternal::ButtonFn");
750  }
751 
752  // reset number of frames to send new button state for
753  device->Internal->ButtonSentCount = SEND_BUTTON_STATE_FOR_N_FRAMES;
754 }
755 
756 //-------------------------------------------------------------------------------------------------
759 void vtkPlusClariusOEM::vtkInternal::ProgressFn(int progress)
760 {
761  LOG_INFO("Downloading: " << progress << "%");
762 }
763 
764 //-------------------------------------------------------------------------------------------------
768 void vtkPlusClariusOEM::vtkInternal::ErrorFn(CusErrorCode errorCode, const char* err)
769 {
770  LOG_ERROR("A Clarius OEM error occurred " << errorCode << ".Error text was : " << err);
771 }
772 
773 //-------------------------------------------------------------------------------------------------
774 void vtkPlusClariusOEM::vtkInternal::LogUserSettings()
775 {
776  std::stringstream ss;
777  ss << "ProbeSerialNum: " << this->ProbeSerialNum << std::endl;
778  ss << "PathToCert: " << this->PathToCert << std::endl;
779  ss << "ProbeType: " << this->ProbeType << std::endl;
780  ss << "ImagingApplication: " << this->ImagingApplication << std::endl;
781  ss << "FrameSize: [" << this->FrameSize[0] << ", " << this->FrameSize[1] << ", " << this->FrameSize[2] << "]" << std::endl;
782  ss << "EnableAutoGain: " << (this->EnableAutoGain ? "TRUE" : "FALSE") << std::endl;
783  ss << "EnableAutoFocus: " << (this->EnableAutoFocus ? "TRUE" : "FALSE") << std::endl;
784  ss << "Enable5v: " << (this->Enable5v ? "TRUE" : "FALSE") << std::endl;
785  ss << "EnablePenetrationMode: " << (this->EnablePenetrationMode ? "TRUE" : "FALSE") << std::endl;
786  ss << "FreezeOnPoorWifiSignal: " << (this->FreezeOnPoorWifiSignal ? "TRUE" : "FALSE") << std::endl;
787  ss << "KeepAwakeCharging: " << (this->KeepAwakeCharging ? "TRUE" : "FALSE") << std::endl;
788  ss << "PowerButtonsEnabled: " << (this->PowerButtonsEnabled ? "TRUE" : "FALSE") << std::endl;
789  ss << "SoundEnabled: " << (this->SoundEnabled ? "TRUE" : "FALSE") << std::endl;
790  ss << "StationaryTimeoutSec: " << this->StationaryTimeoutSec << std::endl;
791  ss << "WakeOnShake: " << (this->WakeOnShake ? "TRUE" : "FALSE") << std::endl;
792  ss << "ForceLogSend: " << (this->ForceLogSend ? "TRUE" : "FALSE") << std::endl;
793  ss << "EnablePenetrationMode: " << (this->EnablePenetrationMode ? "TRUE" : "FALSE") << std::endl;
794  ss << "ContactDetectionTimeoutSec: " << this->ContactDetectionTimeoutSec << std::endl;
795  ss << "AutoFreezeTimeoutSec: " << this->AutoFreezeTimeoutSec << std::endl;
796  ss << "KeepAwakeTimeoutMin: " << this->KeepAwakeTimeoutMin << std::endl;
797  ss << "UpButtonMode: " << ButtonModeEnumToString[this->UpButtonMode] << std::endl;
798  ss << "DownButtonMode: " << ButtonModeEnumToString[this->DownButtonMode] << std::endl;
799  ss << "ImagingMode: " << this->ImagingModeToString(this->ImagingMode) << std::endl;
800 
801  LOG_INFO(std::endl << "User settings:" << std::endl << ss.str());
802 }
803 
804 //-------------------------------------------------------------------------------------------------
805 // vtkPlusClariusOEM definitions
806 //-------------------------------------------------------------------------------------------------
808 {
809  if (instance == NULL)
810  {
811  instance = new vtkPlusClariusOEM();
812  }
813  return instance;
814 }
815 
816 //-------------------------------------------------------------------------------------------------
818  : Internal(new vtkInternal(this))
819 {
820  this->StartThreadForInternalUpdates = true;
822 
823  this->ImagingParameters->SetDepthMm(DEFAULT_DEPTH_MM);
824  this->ImagingParameters->SetGainPercent(DEFAULT_GAIN_PERCENT);
825  this->ImagingParameters->SetDynRangeDb(DEFAULT_DYNRANGE_PERCENT);
826  this->ImagingParameters->SetTimeGainCompensation(DEFAULT_TGC_DB);
827 
828  // set dummy values to avoid endless error messages when using SlicerOpenIGTLink US Remote Control
829  this->ImagingParameters->SetPowerDb(-1);
832 
833  instance = this;
834 }
835 
836 //-------------------------------------------------------------------------------------------------
838 {
839  // ensure resources released
840  this->InternalDisconnect();
841 
842  if (this->Internal)
843  {
844  delete this->Internal;
845  this->Internal = nullptr;
846  }
847 
848  this->instance = NULL;
849 }
850 
851 //-------------------------------------------------------------------------------------------------
853 {
854  if (instance != NULL)
855  {
856  return instance;
857  }
858  else
859  {
860  // Instance is null, creating new instance
861  instance = new vtkPlusClariusOEM();
862  return instance;
863  }
864 }
865 
866 //-------------------------------------------------------------------------------------------------
867 void vtkPlusClariusOEM::PrintSelf(ostream& os, vtkIndent indent)
868 {
869  LOG_TRACE("vtkPlusClariusOEM::PrintSelf");
870 
871  this->Superclass::PrintSelf(os, indent);
872  os << indent << "ProbeSerialNum: " << this->Internal->ProbeSerialNum << std::endl;
873  os << indent << "PathToCert: " << this->Internal->PathToCert << std::endl;
874  os << indent << "ProbeType: " << this->Internal->ProbeType << std::endl;
875  os << indent << "ImagingApplication: " << this->Internal->ImagingApplication << std::endl;
876  os << indent << "FrameSize: [" << this->Internal->FrameSize[0] << ", " << this->Internal->FrameSize[1] << ", " << this->Internal->FrameSize[2] << "]" << std::endl;
877  os << indent << "EnableAutoGain: " << (this->Internal->EnableAutoGain ? "TRUE" : "FALSE") << std::endl;
878  os << indent << "Enable5v: " << (this->Internal->Enable5v ? "TRUE" : "FALSE") << std::endl;
879  os << indent << "FreezeOnPoorWifiSignal: " << (this->Internal->FreezeOnPoorWifiSignal ? "TRUE" : "FALSE") << std::endl;
880  os << indent << "KeepAwakeCharging: " << (this->Internal->KeepAwakeCharging ? "TRUE" : "FALSE") << std::endl;
881  os << indent << "PowerButtonsEnabled: " << (this->Internal->PowerButtonsEnabled ? "TRUE" : "FALSE") << std::endl;
882  os << indent << "SoundEnabled: " << (this->Internal->SoundEnabled ? "TRUE" : "FALSE") << std::endl;
883  os << indent << "StationaryTimeoutSec: " << this->Internal->StationaryTimeoutSec << std::endl;
884  os << indent << "WakeOnShake: " << (this->Internal->WakeOnShake ? "TRUE" : "FALSE") << std::endl;
885  os << indent << "ForceLogSend: " << (this->Internal->ForceLogSend ? "TRUE" : "FALSE") << std::endl;
886  os << indent << "EnablePenetrationMode: " << (this->Internal->EnablePenetrationMode ? "TRUE" : "FALSE") << std::endl;
887  os << indent << "ContactDetectionTimeoutSec: " << this->Internal->ContactDetectionTimeoutSec << std::endl;
888  os << indent << "AutoFreezeTimeoutSec: " << this->Internal->AutoFreezeTimeoutSec << std::endl;
889  os << indent << "KeepAwakeTimeoutMin: " << this->Internal->KeepAwakeTimeoutMin << std::endl;
890  os << indent << "UpButtonMode: " << ButtonModeEnumToString[this->Internal->UpButtonMode] << std::endl;
891  os << indent << "DownButtonMode: " << ButtonModeEnumToString[this->Internal->DownButtonMode] << std::endl;
892  os << indent << "ImagingMode: " << this->Internal->ImagingModeToString(this->Internal->ImagingMode) << std::endl;
893 }
894 
895 //-------------------------------------------------------------------------------------------------
896 PlusStatus vtkPlusClariusOEM::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
897 {
898  LOG_TRACE("vtkPlusClariusOEM::ReadConfiguration");
899 
900  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
901 
902  // probe serial number
903  XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(
904  ProbeSerialNum, this->Internal->ProbeSerialNum, deviceConfig);
905 
906  // path to Clarius certificate
907  XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(
908  PathToCert, this->Internal->PathToCert, deviceConfig);
909 
910  // probe type
911  XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(
912  ProbeType, this->Internal->ProbeType, deviceConfig);
913  // force probe type string to be entirely uppercase
914  std::transform(
915  this->Internal->ProbeType.begin(),
916  this->Internal->ProbeType.end(),
917  this->Internal->ProbeType.begin(),
918  [](unsigned char c) { return std::toupper(c); }
919  );
920 
921  // imaging application (msk, abdomen, etc.)
922  XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(
923  ImagingApplication, this->Internal->ImagingApplication, deviceConfig);
924  // force imaging application string to be entirely lowercase
925  std::transform(
926  this->Internal->ImagingApplication.begin(),
927  this->Internal->ImagingApplication.end(),
928  this->Internal->ImagingApplication.begin(),
929  [](unsigned char c) { return std::tolower(c); }
930  );
931 
932  // frame size
933  int rfs[2] = { static_cast<int>(DEFAULT_FRAME_SIZE[0]), static_cast<int>(DEFAULT_FRAME_SIZE[1]) };
934  if (deviceConfig->GetVectorAttribute("FrameSize", 2, rfs))
935  {
936  if (rfs[0] < 0 || rfs[1] < 0)
937  {
938  LOG_ERROR("Negative frame size defined in config file. Please define a positive frame size.");
939  return PLUS_FAIL;
940  }
941  FrameSizeType fs = { static_cast<unsigned int>(rfs[0]), static_cast<unsigned int>(rfs[1]), 1 };
942  this->Internal->FrameSize = fs;
943  }
944 
945  // enable auto gain
946  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_OPTIONAL(EnableAutoGain,
947  this->Internal->EnableAutoGain, deviceConfig);
948 
949  // enable 5v rail
950  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_OPTIONAL(Enable5v,
951  this->Internal->Enable5v, deviceConfig);
952 
953  // freeze on poor wifi signal
954  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_OPTIONAL(FreezeOnPoorWifiSignal,
955  this->Internal->FreezeOnPoorWifiSignal, deviceConfig);
956 
957  // keep awake when charging
958  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_OPTIONAL(KeepAwakeCharging,
959  this->Internal->KeepAwakeCharging, deviceConfig);
960 
961  // power buttons enabled
962  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_OPTIONAL(PowerButtonsEnabled,
963  this->Internal->PowerButtonsEnabled, deviceConfig);
964 
965  // sound enabled
966  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_OPTIONAL(SoundEnabled,
967  this->Internal->SoundEnabled, deviceConfig);
968 
969  // freeze when probe is stationary for a specified duration
970  XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_OPTIONAL(int, StationaryTimeoutSec,
971  this->Internal->StationaryTimeoutSec, deviceConfig);
972 
973  // wake on shake
974  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_OPTIONAL(WakeOnShake,
975  this->Internal->WakeOnShake, deviceConfig);
976 
977  // force log send
978  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_OPTIONAL(ForceLogSend,
979  this->Internal->ForceLogSend, deviceConfig);
980 
981  // penetration mode enabled
982  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_OPTIONAL(EnablePenetrationMode,
983  this->Internal->EnablePenetrationMode, deviceConfig);
984 
985  // contact detection timeout (seconds)
986  XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_OPTIONAL(int, ContactDetectionTimeoutSec,
987  this->Internal->ContactDetectionTimeoutSec, deviceConfig);
988 
989  // auto freeze timeout (seconds)
990  XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_OPTIONAL(int, AutoFreezeTimeoutSec,
991  this->Internal->AutoFreezeTimeoutSec, deviceConfig);
992 
993  // keep awake timeout (seconds)
994  XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_OPTIONAL(int, KeepAwakeTimeoutMin,
995  this->Internal->KeepAwakeTimeoutMin, deviceConfig);
996 
997  // deep sleep timeout (hours)
998  XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_OPTIONAL(int, DeepSleepTimeoutHr,
999  this->Internal->DeepSleepTimeoutHr, deviceConfig);
1000 
1001  // up button mode
1002  XML_READ_ENUM3_ATTRIBUTE_NONMEMBER_OPTIONAL(UpButtonMode,
1003  this->Internal->UpButtonMode, deviceConfig,
1004  "FREEZE", BUTTON_MODE::FREEZE,
1005  "USER", BUTTON_MODE::USER,
1006  "DISABLED", BUTTON_MODE::DISABLED
1007  );
1008 
1009  // down button mode
1010  XML_READ_ENUM3_ATTRIBUTE_NONMEMBER_OPTIONAL(DownButtonMode,
1011  this->Internal->DownButtonMode, deviceConfig,
1012  "FREEZE", BUTTON_MODE::FREEZE,
1013  "USER", BUTTON_MODE::USER,
1014  "DISABLED", BUTTON_MODE::DISABLED
1015  );
1016 
1017  // enable auto focus
1018  XML_READ_BOOL_ATTRIBUTE_NONMEMBER_OPTIONAL(EnableAutoFocus,
1019  this->Internal->EnableAutoFocus, deviceConfig);
1020 
1021  // imaging mode
1022  XML_READ_ENUM_ATTRIBUTE_NONMEMBER_OPTIONAL(ImagingMode, this->Internal->ImagingMode, deviceConfig, this->Internal->ImagingModeToString, 0, ImagingModeStrings.size());
1023 
1024  // read imaging parameters
1025  this->ImagingParameters->ReadConfiguration(deviceConfig);
1026 
1027  // validate data sources
1028  XML_FIND_NESTED_ELEMENT_REQUIRED(dataSourcesElement, deviceConfig, "DataSources");
1029  int numSources = dataSourcesElement->GetNumberOfNestedElements();
1030  for (int i = 0; i < numSources; ++i)
1031  {
1032  vtkXMLDataElement* element = dataSourcesElement->GetNestedElement(i);
1033  if (!igsioCommon::IsEqualInsensitive(element->GetName(), "DataSource"))
1034  {
1035  // if this is not a data source element, skip it
1036  continue;
1037  }
1038 
1039  // if video source, verify correct orientation (MF) to place the (0, 0) voxel
1040  // of the image in the marked corner adjacent to the probe
1041  const char* type = element->GetAttribute("Type");
1042  if (type && igsioCommon::IsEqualInsensitive(type, "Video"))
1043  {
1044  const char* orientation = element->GetAttribute("PortUsImageOrientation");
1045  if (orientation && !igsioCommon::IsEqualInsensitive(orientation, "UF"))
1046  {
1047  LOG_WARNING("Clarius image source has unexpected value '" << orientation << "' for PortUsImageOrientation. Please confirm your image orientation, expected value for most Clarius probes is 'UF'.");
1048  }
1049  }
1050 
1051  // if tool, verify port name is a valid option for Clarius OEM
1052  if (type && igsioCommon::IsEqualInsensitive(type, "Tool"))
1053  {
1054  const char* toolId = element->GetAttribute("Id");
1055  if (toolId == NULL)
1056  {
1057  LOG_ERROR("Failed to initialize Clarius OEM transform: DataSource Id is missing");
1058  return PLUS_FAIL;
1059  }
1060 
1061  const char* portName = element->GetAttribute("PortName");
1062  if (portName && !igsioCommon::IsEqualInsensitive(portName, TRANSD_PORT_NAME))
1063  {
1064  LOG_ERROR("Clarius OEM device only supports Tool items with PortName=\""
1065  << TRANSD_PORT_NAME << "\"");
1066  return PLUS_FAIL;
1067  }
1068 
1069  // set vtkInternal pointer to transd transform source
1070  igsioTransformName transdTransformName(toolId, this->GetToolReferenceFrameName());
1071  std::string transdSourceId = transdTransformName.GetTransformName();
1072  if (this->GetTool(transdSourceId, this->Internal->TransdSource) != PLUS_SUCCESS || this->Internal->TransdSource == NULL)
1073  {
1074  LOG_ERROR("Failed to get ClariusOEM tool: " << transdSourceId);
1075  return PLUS_FAIL;
1076  }
1077  }
1078  }
1079 
1080  // set vtkInternal pointer to b-mode data source
1081  this->GetVideoSourcesByPortName(vtkPlusDevice::BMODE_PORT_NAME, this->Internal->BModeSources);
1082  this->GetVideoSourcesByPortName(vtkPlusClariusOEM::OVERLAY_PORT_NAME, this->Internal->OverlaySources);
1083 
1084  return PLUS_SUCCESS;
1085 }
1086 
1087 //-------------------------------------------------------------------------------------------------
1088 PlusStatus vtkPlusClariusOEM::WriteConfiguration(vtkXMLDataElement* rootConfigElement)
1089 {
1090  LOG_TRACE("vtkPlusClariusOEM::WriteConfiguration");
1091 
1092  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
1093 
1094  this->ImagingParameters->WriteConfiguration(deviceConfig);
1095 
1096  return PLUS_SUCCESS;
1097 }
1098 
1099 //-------------------------------------------------------------------------------------------------
1101 {
1102  LOG_TRACE("vtkPlusClariusOEM::NotifyConfigured");
1103 
1105  if (device->OutputChannels.size() > 1)
1106  {
1107  LOG_WARNING("vtkPlusClariusOEM is expecting one output channel and there are " <<
1108  this->OutputChannels.size() << " channels. First output channel will be used.");
1109  }
1110 
1111  if (device->OutputChannels.empty())
1112  {
1113  LOG_ERROR("No output channels defined for vtkPlusClariusOEM. Cannot proceed.");
1114  this->CorrectlyConfigured = false;
1115  return PLUS_FAIL;
1116  }
1117 
1118  std::vector<vtkPlusDataSource*> sources;
1119  sources = device->GetVideoSources();
1120  if (sources.size() > 1)
1121  {
1122  LOG_WARNING("More than one output video source found. First will be used");
1123  }
1124  if (sources.size() == 0)
1125  {
1126  LOG_ERROR("Video source required in configuration. Cannot proceed.");
1127  return PLUS_FAIL;
1128  }
1129 
1130  // Check if output channel has data source
1131  vtkPlusDataSource* aSource(NULL);
1132  if (device->OutputChannels[0]->GetVideoSource(aSource) != PLUS_SUCCESS)
1133  {
1134  LOG_ERROR("Unable to retrieve the video source in the vtkPlusClariusOEM device.");
1135  return PLUS_FAIL;
1136  }
1137 
1138  return PLUS_SUCCESS;
1139 }
1140 
1141 //-------------------------------------------------------------------------------------------------
1143 {
1144  LOG_TRACE("vtkPlusClariusOEM: Probe");
1145  LOG_ERROR("vtkPlusClariusOEM::Probe() is not implemented");
1146 
1147  return PLUS_SUCCESS;
1148 };
1149 
1150 //-------------------------------------------------------------------------------------------------
1152 {
1153  LOG_TRACE("vtkPlusClariusOEM::GetSdkVersion");
1154  return "SDK version not available";
1155 }
1156 
1157 //-------------------------------------------------------------------------------------------------
1159 {
1160  LOG_TRACE("vtkPlusClariusOEM::InitializeBLE");
1161 
1162  // find probe by serial number
1163  if (!this->Internal->BleHelper.FindBySerial(this->Internal->ProbeSerialNum))
1164  {
1165  LOG_ERROR("Failed to find BLE connection for Clarius probe with serial number "
1166  << this->Internal->ProbeSerialNum << ". Please make sure the probe is charged"
1167  ", paired, and in range for BLE.");
1168 
1169  std::vector<std::string> probes = this->Internal->BleHelper.RetrieveFoundProbeIds();
1170 
1171  if (!probes.size())
1172  {
1173  // failed to connect to probe by serial number, no active probes found in BLE range
1174  LOG_ERROR("No active Clarius probes found within BLE range");
1175  return PLUS_FAIL;
1176  }
1177 
1178  // print list of nearby active probes
1179  std::stringstream ss;
1180  ss << "Clarius probes configured with Windows Bluetooth are:\n";
1181  for (const std::string& probe : probes)
1182  {
1183  ss << "\t" << probe << "\n";
1184  }
1185  LOG_ERROR(ss.str());
1186  return PLUS_FAIL;
1187  }
1188 
1189  // attempt to connect to probe ble network
1190  LOG_INFO("Connecting to BLE network of Clarius probe with SN: " << this->Internal->ProbeSerialNum);
1191  if (this->Internal->BleHelper.Connect() != PLUS_SUCCESS)
1192  {
1193  LOG_ERROR("Failed to connect to Clarius probe. Last error was: "
1194  << this->Internal->BleHelper.GetLastError());
1195  return PLUS_FAIL;
1196  }
1197 
1198  // double check probe is connected
1199  if (!this->Internal->BleHelper.IsProbeConnected())
1200  {
1201  LOG_ERROR("Failed to connect to Clarius probe. Last error was: "
1202  << this->Internal->BleHelper.GetLastError());
1203  return PLUS_FAIL;
1204  }
1205 
1206  // BLE connection succeeded
1207  return PLUS_SUCCESS;
1208 }
1209 
1210 //-------------------------------------------------------------------------------------------------
1212 {
1213  LOG_TRACE("vtkPlusClariusOEM::InitializeProbe");
1214 
1215  // power on the probe
1216  if (this->Internal->BleHelper.RequestProbeOn() != PLUS_SUCCESS)
1217  {
1218  LOG_ERROR("An error occurred during RequestProbeOn. Last error was: "
1219  << this->Internal->BleHelper.GetLastError());
1220  return PLUS_FAIL;
1221  }
1222 
1223  // wait for probe to fully power on
1224  if (!this->Internal->BleHelper.AwaitWifiInfoReady())
1225  {
1226  LOG_ERROR("Timeout occurred while waiting for Clarius probe to power on."
1227  << " Last error was: " << this->Internal->BleHelper.GetLastError());
1228  return PLUS_FAIL;
1229  }
1230 
1231  // force wifi into AP mode
1232  if (this->Internal->BleHelper.ConfigureWifiAP() != PLUS_SUCCESS)
1233  {
1234  LOG_ERROR("An error occurred during ConfigureWifiAP. Last error was: "
1235  << this->Internal->BleHelper.GetLastError());
1236  return PLUS_FAIL;
1237  }
1238 
1239  // get & print wifi info
1240  std::pair<bool, ClariusWifiInfo> infoPair = this->Internal->BleHelper.GetWifiInfo();
1241  if (!infoPair.first)
1242  {
1243  LOG_ERROR("An error occurred during GetWifiInfo. Last error was: "
1244  << this->Internal->BleHelper.GetLastError());
1245  return PLUS_FAIL;
1246  }
1247 
1248  ClariusWifiInfo info = infoPair.second;
1249  if (!info.Ready)
1250  {
1251  LOG_ERROR("Wifi was not ready when connection info was requested");
1252  return PLUS_FAIL;
1253  }
1254  else
1255  {
1256  std::stringstream infoStream;
1257  infoStream << "\tAvailable: " << to_string(info.Available) << "\n";
1258  infoStream << "\tWifi Mode: " << to_string(info.WifiMode) << "\n";
1259  infoStream << "\tSSID: " << info.SSID << "\n";
1260  infoStream << "\tPassword: " << info.Password << "\n";
1261  infoStream << "\tIPv4: " << info.IPv4 << "\n";
1262  infoStream << "\tMac Address: " << info.MacAddress << "\n";
1263  infoStream << "\tControl Port: " << info.ControlPort << "\n";
1264  infoStream << "\tCast Port: " << info.CastPort << "\n";
1265  infoStream << "\tChannel: " << info.Channel << "\n";
1266 
1267  LOG_INFO("Clarius Wifi Info: " << std::endl << infoStream.str());
1268 
1269  this->Internal->Ssid = info.SSID;
1270  this->Internal->Password = info.Password;
1271  this->Internal->IpAddress = info.IPv4;
1272  this->Internal->TcpPort = info.ControlPort;
1273 
1274  // Remove leading/trailing quotes from SSID
1275  if (this->Internal->Ssid[0] == '"')
1276  {
1277  this->Internal->Ssid = this->Internal->Ssid.substr(1, this->Internal->Ssid.size() - 2);
1278  }
1279  // Remove leading/trailing quotes from password
1280  if (this->Internal->Password[0] == '"')
1281  {
1282  this->Internal->Password = this->Internal->Password.substr(1, this->Internal->Password.size() - 2);
1283  }
1284  // Remove leading/trailing quotes from IP address
1285  if (this->Internal->IpAddress[0] == '"')
1286  {
1287  this->Internal->IpAddress = this->Internal->IpAddress.substr(1, this->Internal->IpAddress.size() - 2);
1288  }
1289 
1290  }
1291 
1292  return PLUS_SUCCESS;
1293 }
1294 
1295 //-------------------------------------------------------------------------------------------------
1297 {
1298  LOG_TRACE("vtkPlusClariusOEM::InitializeWifi");
1299 
1300  if (this->Internal->WifiHelper.Initialize() != PLUS_SUCCESS)
1301  {
1302  LOG_ERROR("Failed to initialize Clarius wifi helper");
1303  return PLUS_FAIL;
1304  }
1305 
1306  PlusStatus res = this->Internal->WifiHelper.ConnectToClariusWifi(
1307  this->Internal->Ssid,
1308  this->Internal->Password
1309  );
1310  if (res != PLUS_SUCCESS)
1311  {
1312  LOG_ERROR("Failed to connect to Clarius probe wifi");
1313  return PLUS_FAIL;
1314  }
1315 
1316  return PLUS_SUCCESS;
1317 }
1318 
1319 //-------------------------------------------------------------------------------------------------
1321 {
1322  LOG_TRACE("vtkPlusClariusOEM::InitializeOEM");
1323 
1324  // placeholder argc / argv arguments
1325  int argc = 1;
1326  char** argv = new char* [1];
1327  argv[0] = new char[4];
1328  strcpy(argv[0], "abc");
1329  const char* certPath = "/Clarius";
1330 
1331  // api callback functions
1332  CusListFn listFnPtr = static_cast<CusListFn>(&vtkPlusClariusOEM::vtkInternal::ListFn);
1333  CusConnectFn connectFnPtr = static_cast<CusConnectFn>(&vtkPlusClariusOEM::vtkInternal::ConnectFn);
1334  CusCertFn certFnPtr = static_cast<CusCertFn>(&vtkPlusClariusOEM::vtkInternal::CertFn);
1335  CusPowerDownFn powerDownFnPtr = static_cast<CusPowerDownFn>(&vtkPlusClariusOEM::vtkInternal::PowerDownFn);
1336  CusSwUpdateFn swUpdateFnPtr = static_cast<CusSwUpdateFn>(&vtkPlusClariusOEM::vtkInternal::SwUpdateFn);
1337  CusNewRawImageFn newRawImageFnPtr = static_cast<CusNewRawImageFn>(&vtkPlusClariusOEM::vtkInternal::RawImageFn);
1338  CusNewProcessedImageFn newProcessedImageFnPtr = static_cast<CusNewProcessedImageFn>(&vtkPlusClariusOEM::vtkInternal::ProcessedImageFn);
1339  CusNewSpectralImageFn newSpectralImageFnPtr = static_cast<CusNewSpectralImageFn>(&vtkPlusClariusOEM::vtkInternal::SpectralImageFn);
1340  CusNewImuDataFn newImuDataFnPtr = static_cast<CusNewImuDataFn>(&vtkPlusClariusOEM::vtkInternal::ImuDataFn);
1341  CusImagingFn imagingFnPtr = static_cast<CusImagingFn>(&vtkPlusClariusOEM::vtkInternal::ImagingFn);
1342  CusButtonFn buttonFnPtr = static_cast<CusButtonFn>(&vtkPlusClariusOEM::vtkInternal::ButtonFn);
1343  CusProgressFn progressFnPtr = static_cast<CusProgressFn>(&vtkPlusClariusOEM::vtkInternal::ProgressFn);
1344  CusErrorFn errorFnPtr = static_cast<CusErrorFn>(&vtkPlusClariusOEM::vtkInternal::ErrorFn);
1345 
1346  // no b-mode data sources, disable b mode callback
1347  std::vector<vtkPlusDataSource*> bModeSources;
1349  if (this->Internal->BModeSources.empty() && this->Internal->OverlaySources.empty())
1350  {
1351  newProcessedImageFnPtr = nullptr;
1352  }
1353 
1354  // no RF-mode data sources, disable RF-mode callback
1355  std::vector<vtkPlusDataSource*> rfModeSources;
1357  if (rfModeSources.empty())
1358  {
1359  newRawImageFnPtr = nullptr;
1360  }
1361 
1362  try
1363  {
1364  FrameSizeType fs = this->Internal->FrameSize;
1365  CusInitParams initParams;
1366  initParams.storeDir = certPath;
1367  initParams.connectFn = connectFnPtr;
1368  initParams.certFn = certFnPtr;
1369  initParams.powerDownFn = powerDownFnPtr;
1370  initParams.newRawImageFn = newRawImageFnPtr;
1371  initParams.newProcessedImageFn = newProcessedImageFnPtr;
1372  initParams.newSpectralImageFn = newSpectralImageFnPtr;
1373  initParams.newImuDataFn = newImuDataFnPtr;
1374  initParams.imagingFn = imagingFnPtr;
1375  initParams.buttonFn = buttonFnPtr;
1376  initParams.errorFn = errorFnPtr;
1377  initParams.newImuPortFn = nullptr;
1378  initParams.newImuDataFn = nullptr;
1379  initParams.width = fs[0];
1380  initParams.height = fs[1];
1381 
1382  CusInitParams::Args initArgs;
1383  initArgs.argc = argc;
1384  initArgs.argv = argv;
1385  initParams.args = initArgs;
1386 
1387  int result = solumInit(&initParams);
1388 
1389  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1390 
1391  if (result < 0)
1392  {
1393  LOG_ERROR("Failed to initialize Clarius OEM library");
1394  return PLUS_FAIL;
1395  }
1396  }
1397  catch (const std::runtime_error& re)
1398  {
1399  LOG_ERROR("Runtime error on solumInit. Error text: " << re.what());
1400  return PLUS_FAIL;
1401  }
1402  catch (const std::exception& ex)
1403  {
1404  LOG_ERROR("Exception on solumInit. Error text: " << ex.what());
1405  return PLUS_FAIL;
1406  }
1407  catch (...)
1408  {
1409  LOG_ERROR("Unknown failure occurred on solumInit");
1410  return PLUS_FAIL;
1411  }
1412 
1413  return PLUS_SUCCESS;
1414 
1415 }
1416 
1417 //-------------------------------------------------------------------------------------------------
1419 {
1420  LOG_TRACE("vtkPlusClariusOEM::SetClariusCert");
1421 
1422  // load the cert file
1423  std::string fullCertPath = vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationPath(this->Internal->PathToCert);
1424  std::ifstream certFile(fullCertPath);
1425  if (!certFile.is_open())
1426  {
1427  LOG_ERROR("Failed to open Clarius cert file from " << fullCertPath << ". Please check the PathToCert path in your config.");
1428  return PLUS_FAIL;
1429  }
1430 
1431  std::ostringstream sstr;
1432  sstr << certFile.rdbuf();
1433  std::string certStr = sstr.str();
1434 
1435  // set cert in OEM API
1436  if (solumSetCert(certStr.c_str()) != 0)
1437  {
1438  LOG_ERROR("Failed to set Clarius OEM connection certificate");
1439  return PLUS_FAIL;
1440  }
1441  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1442 
1443  return PLUS_SUCCESS;
1444 }
1445 
1446 //-------------------------------------------------------------------------------------------------
1448 {
1449  const char* ip = this->Internal->IpAddress.c_str();
1450  unsigned int port = this->Internal->TcpPort;
1451  LOG_INFO("Attempting connection to Clarius ultrasound on " << ip << ":" << port << " for 25 seconds:");
1452 
1453  std::future<void> connectionBarrierFuture = this->Internal->ConnectionBarrier.get_future();
1454  try
1455  {
1456  CusConnectionParams connParams;
1457  connParams.ipAddress = ip;
1458  connParams.port = port;
1459  int result = solumConnect(&connParams);
1460  if (result != CusConnection::ProbeConnected)
1461  {
1462  LOG_ERROR("Failed to initiate connection to Clarius probe on " << ip << ":" << port <<
1463  ". Return code: " << ConnectEnumToString[result]);
1464  return PLUS_FAIL;
1465  }
1466  }
1467  catch (const std::runtime_error& re)
1468  {
1469  LOG_ERROR("Runtime error on solumConnect. Error text: " << re.what());
1470  return PLUS_FAIL;
1471  }
1472  catch (const std::exception& ex)
1473  {
1474  LOG_ERROR("Exception on solumConnect. Error text: " << ex.what());
1475  return PLUS_FAIL;
1476  }
1477  catch (...)
1478  {
1479  LOG_ERROR("Unknown failure occurred on solumConnect");
1480  return PLUS_FAIL;
1481  }
1482 
1483  // wait for solumConnected call to complete
1484  if (connectionBarrierFuture.wait_for(std::chrono::seconds(25)) != std::future_status::ready)
1485  {
1486  LOG_ERROR("Connection to Clarius device timed out");
1487  return PLUS_FAIL;
1488  }
1489  LOG_INFO("Connected to Clarius probe on " << ip << ":" << port);
1490 
1491  // get list of available probes
1492  CusListFn listFnPtr = static_cast<CusListFn>(&vtkPlusClariusOEM::vtkInternal::ListFn);
1493  this->Internal->ExpectedList = vtkPlusClariusOEM::vtkInternal::EXPECTED_LIST::PROBES;
1494  std::future<std::vector<std::string>> futureProbes = this->Internal->PromiseProbes.get_future();
1495  if (solumProbes(listFnPtr) != 0)
1496  {
1497  LOG_INFO("Failed to retrieve list of valid probe types");
1498  return PLUS_FAIL;
1499  }
1500  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1501 
1502  // wait for probes list to be populated
1503  if (futureProbes.wait_for(std::chrono::seconds(5)) != std::future_status::ready)
1504  {
1505  LOG_ERROR("Failed to retrieve list of valid Clarius probe names");
1506  return PLUS_FAIL;
1507  }
1508  std::vector<std::string> vProbes = futureProbes.get();
1509 
1510  // validate provided probe type
1511  std::string probeType = this->Internal->ProbeType;
1512  if (std::find(vProbes.begin(), vProbes.end(), probeType) == vProbes.end())
1513  {
1514  std::string vProbesStr;
1515  for (const auto& probe : vProbes)
1516  {
1517  vProbesStr += probe + ", ";
1518  }
1519  vProbesStr.pop_back(); vProbesStr.pop_back(); // remove trailing comma and space
1520  LOG_ERROR("Invalid probe type (" << probeType << ") provided, valid probe types are: " << vProbesStr);
1521  return PLUS_FAIL;
1522  }
1523 
1524  // list available imaging applications
1525  this->Internal->ExpectedList = vtkPlusClariusOEM::vtkInternal::EXPECTED_LIST::APPLICATIONS;
1526  std::future<std::vector<std::string>> futureApplications = this->Internal->PromiseApplications.get_future();
1527  if (solumApplications(probeType.c_str(), listFnPtr) != 0)
1528  {
1529  LOG_ERROR("Failed to retrieve list of valid imaging applications");
1530  return PLUS_FAIL;
1531  }
1532  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1533 
1534  // wait for applications list to be populated
1535  if (futureApplications.wait_for(std::chrono::seconds(5)) != std::future_status::ready)
1536  {
1537  LOG_ERROR("Failed to retrieve list of valid Clarius application names");
1538  return PLUS_FAIL;
1539  }
1540  std::vector<std::string> vApps = futureApplications.get();
1541 
1542  // validate provided imaging application
1543  std::string imagingApplication = this->Internal->ImagingApplication;
1544  if (std::find(vApps.begin(), vApps.end(), imagingApplication) == vApps.end())
1545  {
1546  std::string vAppsStr;
1547  for (const auto& app : vApps)
1548  {
1549  vAppsStr += app + ", ";
1550  }
1551  vAppsStr.pop_back(); vAppsStr.pop_back(); // remove trailing comma and space
1552  LOG_ERROR("Invalid imaging application (" << imagingApplication << ") provided, valid imaging applications are: " << vAppsStr);
1553  return PLUS_FAIL;
1554  }
1555 
1556  // configure probe mode
1557  if (solumLoadApplication(probeType.c_str(), imagingApplication.c_str()) == 0)
1558  {
1559  LOG_INFO("Loaded " << imagingApplication << " application on a " << probeType << " probe");
1560  }
1561  else
1562  {
1563  LOG_ERROR("An error occured on call to solumLoadApplication");
1564  }
1565  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1566 
1567  return PLUS_SUCCESS;
1568 }
1569 
1570 //-------------------------------------------------------------------------------------------------
1572 {
1573  LOG_TRACE("vtkPlusClariusOEM::SetInitialUsParams");
1574 
1575  // set imaging depth (mm)
1576  double depthMm = this->ImagingParameters->GetDepthMm();
1577  if (this->SetDepthMm(depthMm) != PLUS_SUCCESS)
1578  {
1579  LOG_WARNING("Failed to set requested imaging depth (mm) in Clarius OEM device, unknown depth will be used");
1580  }
1581 
1582  // set gain (%)
1583  double gainPercent = this->ImagingParameters->GetGainPercent();
1584  if (this->SetGainPercent(gainPercent) != PLUS_SUCCESS)
1585  {
1586  LOG_WARNING("Failed to set requested imaging gain (%) in Clarius OEM device, unknown gain will be used");
1587  }
1588 
1589  // set dynamic range (%)
1590  double dynRangePercent = this->ImagingParameters->GetDynRangeDb();
1591  if (this->SetDynRangePercent(dynRangePercent) != PLUS_SUCCESS)
1592  {
1593  LOG_WARNING("Failed to set requested imaging dynamic range in Clarius OEM device, unknown dynamic range will be used");
1594  }
1595 
1596  // set time gain compensation
1597  std::vector<double> tgcDb = this->ImagingParameters->GetTimeGainCompensation();
1598  if (this->SetTimeGainCompensationDb(tgcDb) != PLUS_SUCCESS)
1599  {
1600  LOG_WARNING("Failed to set requested imaging time gain compensation in Clarius OEM device, unknown time gain compensation will be used");
1601  }
1602 
1603  if (this->SetEnableAutoFocus(this->Internal->EnableAutoFocus) != PLUS_SUCCESS)
1604  {
1605  LOG_WARNING("Failed to set auto focus");
1606  }
1607 
1608  if (this->SetEnableAutoGain(this->Internal->EnableAutoGain) != PLUS_SUCCESS)
1609  {
1610  LOG_WARNING("Failed to set auto gain");
1611  }
1612 
1613  if (this->SetEnablePenetrationMode(this->Internal->EnablePenetrationMode) != PLUS_SUCCESS)
1614  {
1615  LOG_WARNING("Failed to set penetration mode");
1616  }
1617 
1618  return PLUS_SUCCESS;
1619 }
1620 
1621 //-------------------------------------------------------------------------------------------------
1623 {
1624  LOG_TRACE("vtkPlusClariusOEM::InternalConnect");
1625 
1626  if (this->Connected)
1627  {
1628  // Internal connect already called and completed successfully
1629  return PLUS_SUCCESS;
1630  }
1631 
1632  // log user settings for debugging
1633  this->Internal->LogUserSettings();
1634 
1635  // BLE
1636  if (this->InitializeBLE() != PLUS_SUCCESS)
1637  {
1638  LOG_ERROR("Failed to initialize BLE in Clarius OEM device");
1639  this->InternalDisconnect();
1640  return PLUS_FAIL;
1641  }
1642 
1643  // PROBE (power, etc.)
1644  if (this->InitializeProbe() != PLUS_SUCCESS)
1645  {
1646  LOG_ERROR("Failed to initialize probe (power, wifi settings) in Clarius OEM device");
1647  this->InternalDisconnect();
1648  return PLUS_FAIL;
1649  }
1650 
1651  // WIFI
1652  if (this->InitializeWifi() != PLUS_SUCCESS)
1653  {
1654  LOG_ERROR("Failed to initialize wifi in Clarius OEM device");
1655  this->InternalDisconnect();
1656  return PLUS_FAIL;
1657  }
1658 
1659  // OEM library
1660  if (this->InitializeOEM() != PLUS_SUCCESS)
1661  {
1662  LOG_ERROR("Failed to initialize OEM library in Clarius OEM device");
1663  this->InternalDisconnect();
1664  return PLUS_FAIL;
1665  }
1666 
1667  // SET CERTIFICATE
1668  if (this->SetClariusCert() != PLUS_SUCCESS)
1669  {
1670  LOG_ERROR("Failed to set Clarius certificate. Please check your PathToCert is valid, and contains the correct cert for the probe you're connecting to");
1671  this->InternalDisconnect();
1672  return PLUS_FAIL;
1673  }
1674 
1675  // CONFIGURE PROBE SETTINGS
1676  CusProbeSettings settings;
1677  settings.contactDetection = this->Internal->ContactDetectionTimeoutSec;
1678  settings.autoFreeze = this->Internal->AutoFreezeTimeoutSec;
1679  settings.keepAwake = this->Internal->KeepAwakeTimeoutMin;
1680  settings.deepSleep = this->Internal->DeepSleepTimeoutHr;
1681  settings.stationary = this->Internal->StationaryTimeoutSec;
1682  settings.wifiOptimization = this->Internal->FreezeOnPoorWifiSignal;
1683  // settings.wifiSearch
1684  // settings.htWifi
1685  settings.keepAwakeCharging = this->Internal->KeepAwakeCharging;
1686  settings.powerOn = this->Internal->PowerButtonsEnabled;
1687  settings.sounds = this->Internal->SoundEnabled;
1688  settings.wakeOnShake = this->Internal->WakeOnShake;
1689  // settings.bandwidthOptimization
1690  settings.forceLogSend = this->Internal->ForceLogSend;
1691  settings.up = static_cast<CusButtonSetting>(this->Internal->UpButtonMode);
1692  settings.down = static_cast<CusButtonSetting>(this->Internal->DownButtonMode);
1693  settings.handle = CusButtonSetting::ButtonDisabled;
1694  settings.upHold = CusButtonHoldSetting::ButtonHoldDisabled;
1695  settings.downHold = CusButtonHoldSetting::ButtonHoldShutdown;
1696  if (solumSetProbeSettings(&settings) != 0)
1697  {
1698  LOG_ERROR("Failed to set Clarius OEM probe settings");
1699  return PLUS_FAIL;
1700  }
1701  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1702 
1703  // CONFIGURE PROBE MODE
1704  if (this->ConfigureProbeApplication() != PLUS_SUCCESS)
1705  {
1706  LOG_ERROR("Failed to configure Clarius probe application");
1707  this->InternalDisconnect();
1708  return PLUS_FAIL;
1709  }
1710 
1711  // PRINT DEVICE STATS AND PROBE INFO
1712  this->UpdateProbeStatus();
1713  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1714 
1715  CusProbeInfo probeInfo;
1716  if (solumProbeInfo(&probeInfo) != 0)
1717  {
1718  LOG_WARNING("Failed to retrieve solumProbeInfo");
1719  }
1720  std::stringstream ss;
1721  ss << "Version: " << probeInfo.version << std::endl;
1722  ss << "Battery: " << this->Internal->CurrentStatus.battery << "%" << std::endl;
1723  ss << "Temperature: " << this->Internal->CurrentStatus.temperature << "%" << std::endl;
1724  ss << "Elements: " << probeInfo.elements << std::endl;
1725  ss << "Pitch: " << probeInfo.pitch << std::endl;
1726  ss << "Radius: " << probeInfo.radius << "mm" << std::endl;
1727  LOG_INFO(std::endl << "Probe info: " << std::endl << ss.str());
1728 
1729  // enable the 5v rail on the top of the Clarius probe
1730  int enable5v = this->Internal->Enable5v ? 1 : 0;
1731  if (solumEnable5v(enable5v) < 0)
1732  {
1733  std::string enstr = (enable5v ? "TRUE" : "FALSE");
1734  LOG_WARNING("Failed to set the state of the Clarius probe 5v rail, provided enable value was: " << enstr);
1735  }
1736  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1737 
1738  // set imaging parameters
1739  this->SetInitialUsParams();
1740 
1741  CusMode mode = CusMode(this->Internal->ImagingMode);
1742  if (solumSetMode(mode) != 0)
1743  {
1744  LOG_ERROR("Failed to set Clarius OEM imaging mode");
1745  return PLUS_FAIL;
1746  }
1747 
1748  // set separate overlays
1749  if (solumSeparateOverlays(1) != 0)
1750  {
1751  LOG_ERROR("Failed to set Clarius separate overlays");
1752  return PLUS_FAIL;
1753  }
1754 
1755  return PLUS_SUCCESS;
1756 };
1757 
1758 //-------------------------------------------------------------------------------------------------
1760 {
1761  LOG_TRACE("vtkPlusClariusOEM::DeInitializeOEM");
1762 
1763  int oemState = solumIsConnected();
1764  if (oemState == CLARIUS_STATE_NOT_INITIALIZED)
1765  {
1766  return;
1767  }
1768 
1769  if (oemState == CLARIUS_STATE_CONNECTED)
1770  {
1771  if (solumEnable5v(CLARIUS_FALSE) < 0)
1772  {
1773  LOG_WARNING("Failed to disable Clarius 5v");
1774  }
1775 
1776  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1777  if (solumRun(CLARIUS_STOP) < 0)
1778  {
1779  LOG_WARNING("Failed to stop Clarius imaging");
1780  }
1781 
1782  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1783  if (solumDisconnect() < 0)
1784  {
1785  LOG_WARNING("Failed to disconnect from Clarius OEM library");
1786  }
1787  }
1788 
1789  if (solumDestroy() < 0)
1790  {
1791  LOG_WARNING("Failed to destroy Clarius OEM library");
1792  }
1793 }
1794 
1795 //-------------------------------------------------------------------------------------------------
1797 {
1798  LOG_TRACE("vtkPlusClariusOEM::DeInitializeWifi");
1799 
1800  if (!this->Internal->WifiHelper.DisconnectFromClariusWifi())
1801  {
1802  LOG_WARNING("Failed to disconnect from Clarius wifi");
1803  }
1804  if (!this->Internal->WifiHelper.DeInitialize())
1805  {
1806  LOG_WARNING("Failed to de-initialize ClariusWifi");
1807  }
1808 }
1809 
1810 //-------------------------------------------------------------------------------------------------
1812 {
1813  LOG_TRACE("vtkPlusClariusOEM::DeInitializeProbe");
1814 
1815  // power off the probe if powered / connected over BLE
1816  if (!this->Internal->BleHelper.IsProbeConnected())
1817  {
1818  return;
1819  }
1820 
1821  if (this->Internal->BleHelper.RequestProbeOff() != PLUS_SUCCESS)
1822  {
1823  LOG_ERROR("An error occurred during RequestProbeOff. Last error was: "
1824  << this->Internal->BleHelper.GetLastError())
1825  }
1826 }
1827 
1828 //-------------------------------------------------------------------------------------------------
1830 {
1831  LOG_TRACE("vtkPlusClariusOEM::DeInitializeBLE");
1832 
1833  // disconnect from probe BLE
1834  if (this->Internal->BleHelper.Disconnect() != PLUS_SUCCESS)
1835  {
1836  LOG_ERROR("An error occurred during Clarius BLE Disconnect. Last error was: "
1837  << this->Internal->BleHelper.GetLastError());
1838  }
1839 }
1840 
1841 //-------------------------------------------------------------------------------------------------
1843 {
1844  LOG_TRACE("vtkPlusClariusOEM::InternalDisconnect");
1845 
1846  // inverse order to initialization
1847  this->DeInitializeOEM();
1848  this->DeInitializeWifi();
1849  this->DeInitializeProbe();
1850  this->DeInitializeBLE();
1851 
1852  return PLUS_SUCCESS;
1853 };
1854 
1855 //-------------------------------------------------------------------------------------------------
1857 {
1858  LOG_TRACE("vtkPlusClariusOEM::InternalStartRecording");
1859 
1860  this->UpdateFrameSize();
1861 
1862  bool running = false;
1863  for (int i = 0; i < 10; ++i)
1864  {
1865  // Attempt to connect. solumRun may not succeed the first time.
1866  if (solumRun(CLARIUS_RUN) < 0)
1867  {
1868  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1869  continue;
1870  }
1871  running = true;
1872  }
1873 
1874  if (!running)
1875  {
1876  LOG_ERROR("Failed to start Clarius imaging");
1877  return PLUS_FAIL;
1878  }
1879  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1880 
1881  return PLUS_SUCCESS;
1882 }
1883 
1884 //----------------------------------------------------------------------------
1886 {
1887  vtkPlusDataSource* videoSource(NULL);
1888  this->GetFirstVideoSource(videoSource);
1889  videoSource->SetInputFrameSize(this->Internal->FrameSize);
1890  videoSource->SetPixelType(VTK_UNSIGNED_CHAR);
1891  unsigned int numberOfScalarComponents = (videoSource->GetImageType() == US_IMG_RGB_COLOR ? 3 : 1);
1892  videoSource->SetNumberOfScalarComponents(numberOfScalarComponents);
1893  return PLUS_SUCCESS;
1894 }
1895 
1896 //-------------------------------------------------------------------------------------------------
1898 {
1899  LOG_TRACE("vtkPlusClariusOEM::InternalStopRecording");
1900 
1901  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
1902  {
1903  // Not connected, so recording is already stopped.
1904  return PLUS_SUCCESS;
1905  }
1906 
1907  if (solumRun(CLARIUS_STOP) < 0)
1908  {
1909  LOG_ERROR("Failed to stop Clarius imaging");
1910  return PLUS_FAIL;
1911  }
1912  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_LONG_DELAY_MS));
1913 
1914  return PLUS_SUCCESS;
1915 }
1916 
1917 //-------------------------------------------------------------------------------------------------
1919 {
1920  LOG_TRACE("vtkPlusClariusOEM::InternalApplyImagingParameterChange");
1921 
1922  PlusStatus status = PLUS_SUCCESS;
1923 
1924  // depth (mm), note: Clarius uses cm
1927  {
1928  if (this->SetDepthMm(this->ImagingParameters->GetDepthMm()) != PLUS_SUCCESS)
1929  {
1930  LOG_ERROR("Failed to set depth imaging parameter");
1931  status = PLUS_FAIL;
1932  }
1934  }
1935 
1936  // gain (percent)
1939  {
1941  {
1942  LOG_ERROR("Failed to set gain imaging parameter");
1943  status = PLUS_FAIL;
1944  }
1946  }
1947 
1948  // dynamic range (percent)
1951  {
1953  {
1954  LOG_ERROR("Failed to set dynamic range imaging parameter");
1955  status = PLUS_FAIL;
1956  }
1958  }
1959 
1960  // TGC (time gain compensation)
1963  {
1964  std::vector<double> tgcVec;
1966  if (this->SetTimeGainCompensationDb(tgcVec) != PLUS_SUCCESS)
1967  {
1968  LOG_ERROR("Failed to set time gain compensation imaging parameter");
1969  status = PLUS_FAIL;
1970  }
1972  }
1973 
1974  // FOCUS DEPTH
1977  {
1979  {
1980  LOG_ERROR("Failed to set focus depth percent imaging parameter");
1981  status = PLUS_FAIL;
1982  }
1984  }
1985 
1986  return status;
1987 }
1988 
1989 //-------------------------------------------------------------------------------------------------
1991 {
1992  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
1993  {
1994  // Connection has not been established yet, return cached parameter value
1995  return this->ImagingParameters->GetDepthMm(aDepthMm);
1996  }
1997 
1998  double oemVal = solumGetParam(CusParam::ImageDepth);
1999  if (oemVal < 0)
2000  {
2001  aDepthMm = -1;
2002  LOG_ERROR("Failed to get DepthMm parameter");
2003  return PLUS_FAIL;
2004  }
2005  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2006 
2007  aDepthMm = oemVal * CM_TO_MM;
2008 
2009  // ensure ImagingParameters is up to date
2010  this->ImagingParameters->SetDepthMm(aDepthMm);
2011 
2012  return PLUS_SUCCESS;
2013 }
2014 
2015 //-------------------------------------------------------------------------------------------------
2017 {
2018  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2019  {
2020  // Connection has not been established yet, parameter value will be set upon connection
2021  this->ImagingParameters->SetDepthMm(aDepthMm);
2022  LOG_INFO("Cached US parameter DepthMm = " << aDepthMm);
2023  return PLUS_SUCCESS;
2024  }
2025 
2026  // attempt to set parameter value
2027  double depthCm = aDepthMm * MM_TO_CM;
2028  if (solumSetParam(CusParam::ImageDepth, depthCm) < 0)
2029  {
2030  LOG_ERROR("Failed to set DepthMm parameter");
2031  return PLUS_FAIL;
2032  }
2033  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2034 
2035  // update imaging parameters & return successfully
2036  this->ImagingParameters->SetDepthMm(aDepthMm);
2037  LOG_INFO("Set US parameter DepthMm to " << aDepthMm);
2038  return PLUS_SUCCESS;
2039 }
2040 
2041 //-------------------------------------------------------------------------------------------------
2043 {
2044  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2045  {
2046  // Connection has not been established yet, return cached parameter value
2047  return this->ImagingParameters->GetGainPercent(aGainPercent);
2048  }
2049 
2050  double oemVal = solumGetParam(CusParam::Gain);
2051  if (oemVal < 0)
2052  {
2053  aGainPercent = -1;
2054  LOG_ERROR("Failed to get GainPercent parameter");
2055  return PLUS_FAIL;
2056  }
2057  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2058 
2059  aGainPercent = oemVal;
2060 
2061  // ensure ImagingParameters is up to date
2062  this->ImagingParameters->SetGainPercent(aGainPercent);
2063 
2064  return PLUS_SUCCESS;
2065 }
2066 
2067 //-------------------------------------------------------------------------------------------------
2069 {
2070  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2071  {
2072  // Connection has not been established yet, parameter value will be set upon connection
2073  this->ImagingParameters->SetGainPercent(aGainPercent);
2074  LOG_INFO("Cached US parameter GainPercent = " << aGainPercent);
2075  return PLUS_SUCCESS;
2076  }
2077 
2078  // attempt to set parameter value
2079  if (solumSetParam(CusParam::Gain, aGainPercent) < 0)
2080  {
2081  LOG_ERROR("Failed to set GainPercent parameter");
2082  return PLUS_FAIL;
2083  }
2084  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2085 
2086  // update imaging parameters & return successfully
2087  this->ImagingParameters->SetGainPercent(aGainPercent);
2088  LOG_INFO("Set US parameter GainPercent to " << aGainPercent);
2089  return PLUS_SUCCESS;
2090 }
2091 
2092 //-------------------------------------------------------------------------------------------------
2094 {
2095  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2096  {
2097  // Connection has not been established yet, return cached parameter value
2098  return this->ImagingParameters->GetDynRangeDb(aDynRangePercent);
2099  }
2100 
2101  double oemVal = solumGetParam(CusParam::DynamicRange);
2102  if (oemVal < 0)
2103  {
2104  aDynRangePercent = -1;
2105  LOG_ERROR("Failed to get DynRange parameter");
2106  return PLUS_FAIL;
2107  }
2108  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2109 
2110  aDynRangePercent = oemVal;
2111 
2112  // ensure ImagingParameters is up to date
2113  this->ImagingParameters->SetDynRangeDb(aDynRangePercent);
2114 
2115  return PLUS_SUCCESS;
2116 }
2117 
2118 //-------------------------------------------------------------------------------------------------
2120 {
2121  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2122  {
2123  // Connection has not been established yet, parameter value will be set upon connection
2124  this->ImagingParameters->SetDynRangeDb(aDynRangePercent);
2125  LOG_INFO("Cached US parameter DynRangePercent = " << aDynRangePercent);
2126  return PLUS_SUCCESS;
2127  }
2128 
2129  // attempt to set parameter value
2130  if (solumSetParam(CusParam::DynamicRange, aDynRangePercent) < 0)
2131  {
2132  LOG_ERROR("Failed to set DynRange parameter");
2133  return PLUS_FAIL;
2134  }
2135  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2136 
2137  // update imaging parameters & return successfully
2138  this->ImagingParameters->SetDynRangeDb(aDynRangePercent);
2139  LOG_INFO("Set US parameter DynRangePercent to " << aDynRangePercent);
2140  return PLUS_SUCCESS;
2141 }
2142 
2143 //-------------------------------------------------------------------------------------------------
2145 {
2146  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2147  {
2148  // Connection has not been established yet, return cached parameter value
2149  return this->ImagingParameters->GetTimeGainCompensation(aTGC);
2150  }
2151 
2152  CusTgc cTGC;
2153  if (solumGetTgc(&cTGC) < 0)
2154  {
2155  LOG_ERROR("Failed to get time gain compensation parameter");
2156  return PLUS_FAIL;
2157  }
2158  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2159 
2160  aTGC.clear();
2161  aTGC.resize(3);
2162  aTGC[0] = cTGC.top;
2163  aTGC[1] = cTGC.mid;
2164  aTGC[2] = cTGC.bottom;
2165 
2166  // ensure imaging parameters are up to date
2168 
2169  return PLUS_SUCCESS;
2170 }
2171 
2172 //-------------------------------------------------------------------------------------------------
2174 {
2175  if (aTGC.size() != 3)
2176  {
2177  LOG_ERROR("vtkPlusClariusOEM time gain compensation parameter must be provided a vector of exactly 3 doubles [top gain, mid gain, bottom gain]");
2178  return PLUS_FAIL;
2179  }
2180 
2181  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2182  {
2183  // Connection has not been established yet, parameter value will be set upon connection
2185  LOG_INFO("Cached US parameter TGC = [" << aTGC[0] << ", " << aTGC[1] << ", " << aTGC[2] << "]");
2186  return PLUS_SUCCESS;
2187  }
2188 
2189  for (int i = 0; i < 3; ++i)
2190  {
2191  if (std::abs(aTGC[i]) > 20)
2192  {
2193  LOG_ERROR("Invalid time gain compensation parameter at index: " << i << " ["
2194  << aTGC[0] << ", "
2195  << aTGC[1] << ", "
2196  << aTGC[2] << "]. "
2197  << "Valid range is [-20, 20]");
2198  return PLUS_FAIL;
2199  }
2200  }
2201 
2202  CusTgc cTGC;
2203  cTGC.top = aTGC[0];
2204  cTGC.mid = aTGC[1];
2205  cTGC.bottom = aTGC[2];
2206  if (solumSetTgc(&cTGC) < 0)
2207  {
2208  LOG_ERROR("Failed to set time gain compensation parameter");
2209  return PLUS_FAIL;
2210  }
2211  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2212 
2213  // update imaging parameters & return successfully
2215  LOG_INFO("Set US parameter TGC to [" << aTGC[0] << ", " << aTGC[1] << ", " << aTGC[2] << "]");
2216  return PLUS_SUCCESS;
2217 }
2218 
2219 //-------------------------------------------------------------------------------------------------
2221 {
2222  int oemState = solumIsConnected();
2223  if (oemState != CLARIUS_STATE_CONNECTED)
2224  {
2225  // Connection has not been established yet, return cached parameter value
2226  aEnableAutoFocus = this->Internal->EnableAutoFocus;
2227  return PLUS_SUCCESS;
2228  }
2229 
2230  aEnableAutoFocus = solumGetParam(CusParam::AutoFocus) > 0;
2231  return PLUS_SUCCESS;
2232 }
2233 
2234 //-------------------------------------------------------------------------------------------------
2236 {
2237  this->Internal->EnableAutoFocus = aEnableAutoFocus;
2238 
2239  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2240  {
2241  // Connection has not been established yet, parameter value will be set upon connection
2242  LOG_INFO("Cached US parameter AutoFocus = " << aEnableAutoFocus);
2243  return PLUS_SUCCESS;
2244  }
2245 
2246  // attempt to set parameter value
2247  if (solumSetParam(AutoFocus, aEnableAutoFocus ? CLARIUS_TRUE : CLARIUS_FALSE))
2248  {
2249  LOG_ERROR("Failed to set AutoFocus parameter");
2250  return PLUS_FAIL;
2251  }
2252  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2253 
2254  return PLUS_SUCCESS;
2255 }
2256 
2257 //-------------------------------------------------------------------------------------------------
2259 {
2260  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2261  {
2262  // Connection has not been established yet, return cached parameter value
2263  aEnablePenetrationMode = this->Internal->EnablePenetrationMode;
2264  return PLUS_SUCCESS;
2265  }
2266 
2267  aEnablePenetrationMode = solumGetParam(PenetrationMode) > 0;
2268  return PLUS_SUCCESS;
2269 }
2270 
2271 //-------------------------------------------------------------------------------------------------
2273 {
2274  LOG_TRACE("vtkPlusClariusOEM::SetEnablePenetrationMode");
2275 
2276  // attempt to set parameter value
2277  if (solumSetParam(PenetrationMode, aEnablePenetrationMode ? CLARIUS_TRUE : CLARIUS_FALSE))
2278  {
2279  LOG_ERROR("Failed to set PenetrationMode parameter");
2280  return PLUS_FAIL;
2281  }
2282  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2283 
2284  return PLUS_SUCCESS;
2285 }
2286 
2287 //-------------------------------------------------------------------------------------------------
2289 {
2290  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2291  {
2292  // Connection has not been established yet, return cached parameter value
2293  return this->ImagingParameters->GetFocusDepthPercent(aFocusDepthPercent);
2294  }
2295 
2296  double focusDepthCm = solumGetParam(CusParam::FocusDepth);
2297  if (focusDepthCm < 0)
2298  {
2299  aFocusDepthPercent = -1;
2300  LOG_ERROR("Failed to get FocusDepthPercent parameter");
2301  return PLUS_FAIL;
2302  }
2303  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2304 
2305  // ensure ImagingParameters is up to date
2308 
2309  return PLUS_SUCCESS;
2310 }
2311 
2312 //-------------------------------------------------------------------------------------------------
2314 {
2315  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2316  {
2317  // Connection has not been established yet, parameter value will be set upon connection
2318  this->ImagingParameters->SetFocusDepthPercent(aFocusDepthPercent);
2319  LOG_INFO("Cached US parameter FocusDepthPercent = " << aFocusDepthPercent);
2320  return PLUS_SUCCESS;
2321  }
2322 
2323  if (aFocusDepthPercent < 0)
2324  {
2325  this->SetEnableAutoFocus(true);
2326  return PLUS_SUCCESS;
2327  }
2328  this->SetEnableAutoFocus(false);
2329 
2330  double focusDepthCm = this->ConvertDepthPercentToCm(aFocusDepthPercent);
2331 
2332  // attempt to set parameter value
2333  if (solumSetParam(CusParam::FocusDepth, focusDepthCm) < 0)
2334  {
2335  LOG_ERROR("Failed to set FocusDepthPercent parameter");
2336  return PLUS_FAIL;
2337  }
2338  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2339 
2340  // update imaging parameters & return successfully
2341  this->ImagingParameters->SetFocusDepthPercent(aFocusDepthPercent);
2342  LOG_INFO("Set US parameter FocusDepthPercent to " << aFocusDepthPercent);
2343  return PLUS_SUCCESS;
2344 }
2345 
2346 //-------------------------------------------------------------------------------------------------
2348 {
2349  double depthMm = 0.0;
2350  if (this->GetDepthMm(depthMm) != PLUS_SUCCESS)
2351  {
2352  return 0.0;
2353  }
2354  return 100.0 * depthMm / (aFocusDepthCm * CM_TO_MM);
2355 }
2356 
2357 //-------------------------------------------------------------------------------------------------
2358 double vtkPlusClariusOEM::ConvertDepthPercentToCm(double aFocusDepthPercent)
2359 {
2360  double depthMm = 0.0;
2361  if (this->GetDepthMm(depthMm) != PLUS_SUCCESS)
2362  {
2363  return 0.0;
2364  }
2365  return (depthMm * MM_TO_CM) * (aFocusDepthPercent / 100.0);
2366 }
2367 
2368 //-------------------------------------------------------------------------------------------------
2370 {
2371  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2372  {
2373  // Connection has not been established yet, return cached parameter value
2374  aEnableAutoGain = this->Internal->EnableAutoGain;
2375  return PLUS_SUCCESS;
2376  }
2377 
2378  aEnableAutoGain = solumGetParam(CusParam::AutoGain) > 0;
2379  return PLUS_SUCCESS;
2380 }
2381 
2382 //-------------------------------------------------------------------------------------------------
2384 {
2385  this->Internal->EnableAutoGain = aEnableAutoGain;
2386 
2387  if (solumIsConnected() != CLARIUS_STATE_CONNECTED)
2388  {
2389  // Connection has not been established yet, parameter value will be set upon connection
2390  LOG_INFO("Cached US parameter AutoGain = " << aEnableAutoGain);
2391  return PLUS_SUCCESS;
2392  }
2393 
2394  // attempt to set parameter value
2395  if (solumSetParam(AutoGain, aEnableAutoGain ? CLARIUS_TRUE : CLARIUS_FALSE))
2396  {
2397  LOG_ERROR("Failed to set AutoGain parameter");
2398  return PLUS_FAIL;
2399  }
2400  std::this_thread::sleep_for(std::chrono::milliseconds(CLARIUS_SHORT_DELAY_MS));
2401 
2402  return PLUS_SUCCESS;
2403 }
PlusStatus ConfigureProbeApplication()
PlusStatus GetEnablePenetrationMode(bool &aEnablePenetrationMode)
static const std::string RFMODE_PORT_NAME
Definition: vtkPlusDevice.h:68
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *deviceConfig)
#define CLARIUS_RUN
bool IsPending(const std::string &paramName) const
double ConvertDepthCmToPercent(double aFocusDepthMm)
static void BGRA32ToRGB24(int width, int height, unsigned char *s, unsigned char *d)
Definition: PixelCodec.h:260
US_IMAGE_TYPE GetImageType()
PlusStatus UpdateFrameSize()
PlusStatus SetGainPercent(double aGainPercent)
std::string Password
Definition: ClariusBLE.h:46
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
#define CLARIUS_TRUE
PlusStatus InitializeProbe()
Phidget_MeshMode mode
Definition: phidget22.h:1332
igsioStatus PlusStatus
Definition: PlusCommon.h:40
PlusStatus GetFocusDepthPercent(double &aFocusDepthPercent) const
static const std::string BMODE_PORT_NAME
Definition: vtkPlusDevice.h:67
PlusStatus GetDepthMm(double &aDepthMm) const
std::string IPv4
Definition: ClariusBLE.h:47
PlusStatus SetEnableAutoGain(bool aEnableAutoGain)
PlusStatus SetInputFrameSize(unsigned int x, unsigned int y, unsigned int z)
std::vector< vtkPlusDataSource * > GetVideoSources() const
#define CLARIUS_STATE_CONNECTED
bool RequirePortNameInDeviceSetConfiguration
std::string to_string(ClariusAvailability avail)
std::string MacAddress
Definition: ClariusBLE.h:48
PlusStatus UpdateProbeStatus()
vtkPlusUsImagingParameters * ImagingParameters
Store the current imaging parameters.
ClariusAvailability
Definition: ClariusBLE.h:24
for i
PlusStatus SetPending(const std::string &paramName, bool pending)
PlusStatus InternalStartRecording() override
#define PLUS_FAIL
Definition: PlusCommon.h:43
PlusStatus GetGainPercent(double &aGainPercent)
void PrintSelf(ostream &os, vtkIndent indent) override
PlusStatus GetVideoSourcesByPortName(const char *aPortName, std::vector< vtkPlusDataSource * > &sources)
static vtkPlusClariusOEM * New()
PlusStatus NotifyConfigured() override
int port
Definition: phidget22.h:2454
PlusStatus SetPixelType(igsioCommon::VTKScalarPixelType pixelType)
PlusStatus SetTimeGainCompensation(const std::vector< double > &tgc)
#define CLARIUS_STATE_NOT_INITIALIZED
static vtkPlusConfig * GetInstance()
PlusStatus GetGainPercent(double aGainPercent) const
ClariusWifiMode
Definition: ClariusBLE.h:32
PlusStatus GetFirstVideoSource(vtkPlusDataSource *&anImage)
virtual PlusStatus Disconnect()
PlusStatus GetTimeGainCompensation(std::vector< double > &tgc) const
PlusStatus SetPowerDb(double aPower)
PlusStatus SetEnablePenetrationMode(bool aEnablePenetrationMode)
PlusStatus WriteConfiguration(vtkXMLDataElement *config) override
unsigned long FrameNumber
PlusStatus GetDepthMm(double &aDepthMm)
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
static const std::string OVERLAY_PORT_NAME
PlusStatus SetFocusDepthPercent(double aFocusDepthPercent)
PlusStatus GetFocusDepthPercent(double &aFocusDepthPercent)
PlusStatus GetDynRangePercent(double &aDynamicRangePercent)
PlusStatus GetDynRangeDb(double &aDynRangeDb) const
PlusStatus SetGainPercent(double aGainPercent)
PlusStatus SetDynRangePercent(double aDynamicRangePercent)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
PlusStatus SetDynRangeDb(double aDynRangeDb)
ClariusAvailability Available
Definition: ClariusBLE.h:43
PlusStatus ReadConfiguration(vtkXMLDataElement *config) override
PlusStatus GetTimeGainCompensationDb(std::vector< double > &aTGC)
#define CLARIUS_FALSE
PlusStatus InternalUpdate() override
PlusStatus GetEnableAutoGain(bool &aEnableAutoGain)
PlusStatus Probe() override
ClariusWifiMode WifiMode
Definition: ClariusBLE.h:44
std::string GetSdkVersion() override
bool StartThreadForInternalUpdates
#define CLARIUS_STOP
static PlusStatus ConvertToGray(int inputCompression, int width, int height, unsigned char *s, unsigned char *d)
Definition: PixelCodec.h:146
PlusStatus SetDepthMm(double aDepthMm)
PlusStatus SetEnableAutoFocus(bool aEnableAutoFocus)
PlusStatus InternalDisconnect() override
PlusStatus SetFrequencyMhz(double aFrequencyMhz)
ChannelContainer OutputChannels
PlusStatus SetNumberOfScalarComponents(unsigned int numberOfScalarComponents)
PlusStatus SetFocusDepthPercent(double aFocusDepthPercent)
std::string GetDeviceSetConfigurationPath(const std::string &subPath)
PlusStatus SetInitialUsParams()
PlusStatus InternalConnect() override
PlusStatus GetEnableAutoFocus(bool &aEnableAutoFocus)
std::string GetToolReferenceFrameName() const
bool IsSet(const std::string &paramName) const
PlusStatus InternalStopRecording() override
PlusStatus GetTool(const char *aToolSourceId, vtkPlusDataSource *&aTool) const
static vtkPlusClariusOEM * GetInstance()
PlusStatus SetDepthMm(double aDepthMm)
PlusStatus SetTimeGainCompensationDb(const std::vector< double > &aTGC)
Interface to Clarius Ultrasound Devices This class talks with a Clarius US Scanner over the Clarius O...
PlusStatus InternalApplyImagingParameterChange() override
std::string SSID
Definition: ClariusBLE.h:45
double ConvertDepthPercentToCm(double aFocusDepthPercent)
bool CorrectlyConfigured
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *deviceConfig)
Interface to a 3D positioning tool, video source, or generalized data stream.