ac-trigger.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2018 Intel Corporation. All Rights Reserved.
3 
4 #include "ac-trigger.h"
6 #include "l500-device.h"
7 #include "l500-color.h"
8 #include "l500-depth.h"
11 #include "log.h"
12 
13 
14 #ifdef _WIN32
15 #include <windows.h>
16 #include <direct.h>
17 #else
18 #include <sys/stat.h> // mkdir
19 #include <iostream> // std::cout
20 #endif
21 
22 
23 template < class X > struct string_to {};
24 
25 template<>
26 struct string_to< std::string >
27 {
28  static std::string convert( std::string const & s )
29  {
30  return s;
31  }
32 };
33 
34 template<>
35 struct string_to< int >
36 {
37  static int convert( std::string const & s )
38  {
39  char * p_end;
40  auto v = std::strtol( s.data(), &p_end, 10 );
41  if( errno == ERANGE )
42  throw std::out_of_range( "out of range" );
43  if( p_end != s.data() + s.length() )
44  throw std::invalid_argument( "extra characters" );
45  return v;
46  }
47 };
48 
49 template<>
50 struct string_to< bool >
51 {
52  static bool convert( std::string const & s )
53  {
54  if( s.length() == 1 )
55  {
56  char ch = s.front();
57  if( ch == '1' || ch == 'T' )
58  return true;
59  if( ch == '0' || ch == 'F' )
60  return false;
61  }
62  else
63  {
64  if( s == "true" || s == "TRUE" || s == "on" || s == "ON" )
65  return true;
66  if( s == "false" || s == "FALSE" || s == "off" || s == "OFF" )
67  return false;
68  }
69  throw std::invalid_argument( "invalid boolean value '" + s + '\'' );
70  }
71 };
72 
73 
74 template< class T >
75 class env_var
76 {
77  bool _is_set;
79 
80 public:
81  env_var( char const * name, T default_value, std::function< bool( T ) > checker = nullptr )
82  {
83  auto lpsz = getenv( name );
84  _is_set = (lpsz != nullptr);
85  if( _is_set )
86  {
87  try
88  {
89  _value = string_to< T >::convert( lpsz );
90  if( checker && ! checker( _value ) )
91  throw std::invalid_argument( "does not check" );
92  }
93  catch( std::exception const & e )
94  {
95  AC_LOG( ERROR,
96  "Environment variable \"" << name << "\" is set, but its value (\""
97  << lpsz << "\") is invalid (" << e.what()
98  << "); using default of \"" << default_value
99  << "\"" );
100  _is_set = false;
101  }
102  }
103  if( !_is_set )
104  _value = default_value;
105  }
106 
107  bool is_set() const { return _is_set; }
108  T value() const { return _value; }
109 
110  operator T() const { return _value; }
111 };
112 
113 
114 // Returns the current date and time, with the chosen formatting
115 // See format docs here: https://en.cppreference.com/w/cpp/chrono/c/strftime
116 // %T = equivalent to "%H:%M:%S"
117 static std::string now_string( char const * format_string = "%T" )
118 {
119  std::time_t now = std::time( nullptr );
120  auto ptm = localtime( &now );
121  char buf[256];
122  strftime( buf, sizeof( buf ), format_string, ptm );
123  return buf;
124 }
125 
126 
127 
129 {
130  static int n_seconds
131  = env_var< int >( "RS2_AC_SF_RETRY_SECONDS", 2, []( int n ) { return n > 0; } );
132  return n_seconds;
133 }
134 static double get_temp_diff_trigger()
135 {
136  static double d_temp
137  = env_var< int >( "RS2_AC_TEMP_DIFF", 5, []( int n ) { return n >= 0; } ).value();
138  return d_temp;
139 }
140 static std::chrono::seconds get_trigger_seconds()
141 {
142  auto n_seconds = env_var< int >( "RS2_AC_TRIGGER_SECONDS",
143  600, // 10 minutes since last (0 to disable)
144  []( int n ) { return n >= 0; } );
145  // 0 means turn off auto-trigger
146  return std::chrono::seconds( n_seconds );
147 }
148 
149 
150 namespace rs2
151 {
152  static std::ostream & operator<<( std::ostream & os, stream_profile const & sp )
153  {
154  auto spi = sp.get()->profile;
155  os << '[';
156  if( spi )
157  {
158  os << rs2_format_to_string( spi->get_format() );
159  if( auto vsp = dynamic_cast< const librealsense::video_stream_profile * >( spi ) )
160  os << ' ' << vsp->get_width() << 'x' << vsp->get_height();
161  os << " " << spi->get_framerate() << "fps";
162  }
163  os << ']';
164  return os;
165  }
166 }
167 
168 
169 namespace librealsense {
170 namespace ivcam2 {
171 
172 
174  {
175  if( get_trigger_seconds().count() )
176  return true;
177  if( get_temp_diff_trigger() )
178  return true;
179  return false;
180  }
182  {
183  return env_var< bool >( "RS2_AC_AUTO_TRIGGER",
184 #ifdef __arm__
185  false
186 #else
187  false
188 #endif
189  )
191  }
192 
193  ac_trigger::enabler_option::enabler_option( std::shared_ptr< ac_trigger > const & autocal )
194  : super( option_range{ 0,
196  1,
198  : float( RS2_CAH_TRIGGER_MANUAL ) } )
199  , _autocal( autocal )
200  {
201  }
202 
203  ac_trigger::reset_option::reset_option( std::shared_ptr< ac_trigger > const & autocal )
204  : bool_option( false )
205  , _autocal( autocal )
206  {
207  }
208 
210  {
211  if( value == query() )
212  {
213  return;
214  }
215 
216  auto ac = _autocal.lock();
217  if (!ac)
218  throw std::runtime_error( "device no longer exists" );
219 
220  if( value != RS2_CAH_TRIGGER_NOW )
221  {
222  // When auto trigger is on in the environment, we control the timed activation
223  // of AC, and do NOT trigger manual calibration
224  if( value == RS2_CAH_TRIGGER_AUTO )
225  {
226  if( ! is_auto_trigger_possible() )
227  throw invalid_value_exception( "auto trigger is disabled in the environment" );
228  try
229  {
230  if (ac->_dev.get_depth_sensor().is_streaming())
231  ac->_start();
232 
233  super::set(value);
234  }
235  catch (std::exception const & e)
236  {
237  AC_LOG(ERROR, "EXCEPTION caught during start: " << e.what());
238  return;
239  }
240  // else start() will get called on stream start
241  }
242  else
243  {
244  super::set( value );
245  ac->stop();
246  }
247  _record_action( *this );
248  }
249  else
250  {
251  // User wants to trigger it RIGHT NOW
252  // We don't change the actual control value!
253  bool is_depth_streaming(false);
254 
255  is_depth_streaming = ac->_dev.get_depth_sensor().is_streaming();
256 
257  if( is_depth_streaming )
258  {
259  AC_LOG( DEBUG, "Triggering manual calibration..." );
260  ac->trigger_calibration( calibration_type::MANUAL );
261  }
262  else
263  {
264  throw wrong_api_call_sequence_exception( "Cannot trigger calibration: depth sensor is not on!" );
265  }
266  }
267  }
268 
270  {
271  //bool_option::set( value );
272  auto ac = _autocal.lock();
273  if (!ac)
274  throw std::runtime_error( "device no longer exists" );
275 
276  // Reset the calibration so we can do it all over again
277  if (auto color_sensor = ac->_dev.get_color_sensor())
278  color_sensor->reset_calibration();
279  ac->_dev.get_depth_sensor().reset_calibration();
280  ac->_dev.notify_of_calibration_change(RS2_CALIBRATION_SUCCESSFUL);
281  _record_action(*this);
282  }
283 
284 
285  // Implementation class: starts another thread responsible for sending a retry
286  // NOTE that it does this as long as our shared_ptr keeps us alive: once it's gone, if the
287  // retry period elapses then nothing will happen!
289  {
290  std::weak_ptr<ac_trigger> _ac;
291  unsigned _id;
292  char const * const _name;
293 
294  protected:
295  retrier( ac_trigger & ac, char const * name )
296  : _ac( ac.shared_from_this() )
297  , _name( name ? name : "retrier" )
298  {
299  static unsigned id = 0;
300  _id = ++id;
301  }
302 
303  unsigned get_id() const { return _id; }
304  std::shared_ptr <ac_trigger> get_ac() const { return _ac.lock(); }
305  char const * get_name() const { return _name; }
306 
307  static std::string _prefix( std::string const & name, unsigned id )
308  {
309  return to_string() << "... " << now_string() << " " << name << ' ' << id << ": ";
310  }
312  {
313  return _prefix( get_name(), get_id() );
314  }
315 
316  virtual void retry(ac_trigger & trigger)
317  {
318  trigger.trigger_retry();
319  }
320 
321  public:
322  virtual ~retrier()
323  {
324  AC_LOG( DEBUG, _prefix( '~' + std::string(get_name()), get_id() ));
325  }
326 
327  template < class T = retrier >
328  static std::shared_ptr< T > start( ac_trigger & trigger,
329  std::chrono::seconds n_seconds,
330  const char * name = nullptr )
331  {
332  T * r = new T( trigger, name );
333  auto id = r->get_id();
334  name = r->get_name();
335  AC_LOG( DEBUG, r->prefix() << n_seconds.count() << " seconds starting" );
336  auto pr = std::shared_ptr< T >( r );
337  std::weak_ptr< T > weak{ pr };
338  std::thread( [=]() {
339  std::this_thread::sleep_for( n_seconds );
340  auto pr = weak.lock();
341  if( pr && pr->get_id() == id )
342  {
343  try
344  {
345  AC_LOG( DEBUG, _prefix( name, id ) << "triggering" );
346  auto ac = ( (retrier *)pr.get() )->get_ac();
347  if( ac )
348  ( (retrier *)pr.get() )->retry( *ac );
349  }
350  catch( std::exception const & e )
351  {
352  // Unexpected! If we don't handle, we'll crash!
353  AC_LOG( ERROR, "EXCEPTION caught: " << e.what() );
354  }
355  }
356  else
357  AC_LOG( DEBUG,
358  _prefix( name, id )
359  << n_seconds.count() << " seconds are up; nothing needed" );
360  } ).detach();
361  return pr;
362  }
363  };
365  {
366  public:
367  next_trigger( ac_trigger & ac, const char * name )
368  : retrier( ac, name ? name : "next trigger" )
369  {
370  }
371 
372  private:
373  void retry( ac_trigger & trigger ) override
374  {
375  // We start another trigger regardless of what happens next; if a calibration actually
376  // proceeds, it will be cancelled...
377  trigger.schedule_next_calibration();
378  try
379  {
381  }
382  catch( invalid_value_exception const & )
383  {
384  // Invalid conditions for calibration
385  // Error should already have been printed
386  // We should already have the next triggers set -- do nothing else
387  }
388  }
389  };
391  {
392  public:
393  temp_check( ac_trigger & ac, const char * name )
394  : retrier( ac, name ? name : "temp check" )
395  {
396  }
397 
398  private:
399  void retry( ac_trigger & trigger ) override
400  {
401  if( trigger.is_active() )
402  {
403  AC_LOG( DEBUG, "... already active; ignoring" );
404  return;
405  }
406  // We start another trigger regardless of what happens next; if a calibration actually
407  // proceeds, it will be cancelled...
408  trigger.schedule_next_temp_trigger();
409  auto current_temp = trigger.read_temperature();
410  if( current_temp )
411  {
412  auto d_temp = current_temp - trigger._last_temp;
413  if( d_temp >= get_temp_diff_trigger() )
414  {
415  try
416  {
417  AC_LOG( DEBUG, "Delta since last successful calibration is " << d_temp << " degrees Celsius; triggering..." );
419  }
420  catch( invalid_value_exception const & )
421  {
422  // Invalid conditions for calibration
423  // Error should already have been printed
424  // We should already have the next trigger set -- do nothing else
425  }
426  }
427  // We do not update the trigger temperature: it is only updated after calibration
428  }
429  }
430  };
431 
432 
433  /*
434  Temporary (?) class used to direct CAH logs to either console or a special log
435 
436  If RS2_DEBUG_DIR is defined in the environment, we try to create a log file in there
437  that has the name "<pid>.ac_log".
438  */
440  {
441  std::ofstream _f_main;
442  std::ofstream _f_active;
445 
446  public:
447  explicit ac_logger( bool to_stdout = false )
448  : _to_stdout( to_stdout )
449  {
450  using namespace std::chrono;
451 
452 #ifdef WIN32
453  // In the Viewer, a console does not exist (even when run from a console) because
454  // it's a WIN32 application (this can be removed in its CMakeLists.txt) -- so we
455  // need to create one.
456  if( _to_stdout )
457  {
458  if( AttachConsole( ATTACH_PARENT_PROCESS ) || AllocConsole() )
459  write_out( std::string{} ); // for a newline
460  }
461 #endif
462 
463  std::string filename = get_debug_path_base();
464  if( ! filename.empty() )
465  {
466  filename += ".ac_log";
467 
468  _f_main.open( filename );
469  if( _f_main && _to_stdout )
470  write_out( to_string() << "-D- CAH main log is being written to: " << filename );
471  }
472 
474  { this, []( rs2_log_callback * p ) {} } );
475 
476  AC_LOG( DEBUG, "LRS version: " << RS2_API_FULL_VERSION_STR );
477  }
478 
479  static void add_dir_sep( std::string & path )
480  {
481 #ifdef _WIN32
482  char const dir_sep = '\\';
483 #else
484  char const dir_sep = '/';
485 #endif
486  if( ! path.empty() && path.back() != dir_sep )
487  path += dir_sep;
488  }
489 
491  {
493 
494  // If the user has this env var defined, then we write out logs and frames to it
495  // NOTE: The var should end with a directory separator \ or /
496  auto dir_ = getenv( "RS2_DEBUG_DIR" );
497  if( dir_ )
498  {
499  path = dir_;
500  add_dir_sep( path );
501  path += now_string( "%y%m%d.%H%M%S" );
502  }
503 
504  return path;
505  }
506 
508  {
509  _active_dir = get_debug_path_base();
510  if( _active_dir.empty() )
511  return false;
512  add_dir_sep( _active_dir );
513 
514 #ifdef _WIN32
515  auto status = _mkdir( _active_dir.c_str() );
516 #else
517  auto status = mkdir( _active_dir.c_str(), 0700 ); // 0700 = user r/w/x
518 #endif
519 
520  if( status != 0 )
521  {
522  AC_LOG( WARNING,
523  "Failed (" << status << ") to create directory for AC frame data in: " << _active_dir );
524  _active_dir.clear();
525  return false;
526  }
527  return true;
528  }
529 
530  std::string const & get_active_dir() const { return _active_dir; }
531 
532  void open_active()
533  {
534  close_active();
535  if( ! set_active_dir() )
536  return;
537  std::string filename = get_active_dir() + "ac.log";
538  if( _f_main || _to_stdout )
539  AC_LOG( DEBUG, now_string() << " Active calibration log is being written to: " << filename );
540  _f_active.open( filename );
541  if( ! _f_active )
542  AC_LOG( DEBUG, " failed!" );
543  else if( _to_stdout )
544  write_out( to_string() << "-D- CAH active log is being written to: " << filename );
545  }
546 
548  {
549  if( _f_active )
550  {
551  _f_active.close();
552  _f_active.setstate( std::ios_base::failbit ); // so we don't try to write to it
553  _active_dir.clear();
554  if( _f_main )
555  AC_LOG( DEBUG, now_string() << " ... done" );
556  }
557  }
558 
559  void on_log( rs2_log_severity severity, rs2_log_message const & msg ) noexcept override
560  {
561 #ifdef BUILD_EASYLOGGINGPP
562  log_message const & wrapper = (log_message const &)(msg);
563  char const * raw = wrapper.el_msg.message().c_str();
564  if( strncmp( AC_LOG_PREFIX, raw, AC_LOG_PREFIX_LEN ) )
565  return;
566  std::ostringstream ss;
567  ss << "-" << "DIWE"[severity] << "- ";
568  ss << (raw + 5);
569  std::string text = ss.str();
570  if( _to_stdout )
571  write_out( text );
572  if( _f_active )
573  _f_active << text << std::endl;
574  else if( _f_main )
575  _f_main << text << std::endl;
576 #endif
577  }
578 
579  void release() override { delete this; }
580 
581  private:
582  static void write_out( std::string const & s )
583  {
584 #ifdef WIN32
585  HANDLE stdOut = GetStdHandle( STD_OUTPUT_HANDLE );
586  if( stdOut != NULL && stdOut != INVALID_HANDLE_VALUE )
587  {
588  DWORD written = 0;
589  WriteFile( stdOut, s.c_str(), (DWORD)s.length(), &written, NULL );
590  WriteFile( stdOut, "\n", 1, &written, NULL );
591  }
592 #else
593  std::cout << s << std::endl;
594 #endif
595  }
596  };
597 
598 
599  ac_trigger::ac_trigger( l500_device & dev, std::shared_ptr<hw_monitor> hwm )
600  : _hwm( hwm )
601  , _dev( dev )
602  {
603  get_ac_logger();
604  }
605 
606 
608  {
609  static ac_logger one_logger(
610  env_var< bool >( "RS2_AC_LOG_TO_STDOUT", false ) // log to stdout
611  );
612  return one_logger;
613  }
614 
615 
617  {
618  if( _worker.joinable() )
619  {
620  _is_processing = false; // Signal the thread that we want to stop!
621  _is_on = false; // Set auto calibration off so it won't retry.
622  _worker.join();
623  }
624  }
625 
626 
628  {
630  for( auto && cb : _callbacks )
631  cb( status );
632  }
633 
634 
636  {
637  _retrier.reset();
638  if( ! is_active() )
639  {
640  AC_LOG( ERROR, "Retry attempted but we're not active; ignoring" );
641  return;
642  }
644  {
645  AC_LOG( ERROR, "Failed to receive stable RGB frame; cancelling calibration" );
647  return;
648  }
649 
650  try
651  {
653  }
654  catch( invalid_value_exception const & )
655  {
656  //AC_LOG( ERROR, "Cancelling calibration" );
658  return;
659  }
660 
661  if( _recycler )
662  {
663  // This is another cycle of AC, after we've woken up from some time after
664  // the previous invalid-scene or bad-result...
665  _n_retries = 0;
666  _recycler.reset();
667  }
668  else if( ++_n_retries > 4 )
669  {
670  AC_LOG( ERROR, "Too many retries; aborting" );
672  return;
673  }
674 
676 
679  {
680  AC_LOG( DEBUG, "Waiting for RGB stability before asking for special frame" );
681  _retrier = retrier::start( *this, std::chrono::seconds( get_retry_sf_seconds() + 1 ) );
682  }
683  else
684  {
685  AC_LOG( DEBUG, "Sending GET_SPECIAL_FRAME (cycle " << _n_cycles << " retry " << _n_retries << ")" );
687  }
688  }
689 
690 
692  {
693  command cmd{ GET_SPECIAL_FRAME, 0x5F, 1 }; // 5F = SF = Special Frame, for easy recognition
694  try
695  {
696  auto hwm = _hwm.lock();
697  if( ! hwm )
698  {
699  AC_LOG( ERROR, "Hardware monitor is inaccessible - calibration not triggered" );
700  return;
701  }
702  hwm->send( cmd );
703  }
704  catch( std::exception const & e )
705  {
706  AC_LOG( ERROR, "EXCEPTION caught: " << e.what() );
707  }
708  // Start a timer: enable retries if something's wrong with the special frame
709  if( is_active() )
710  _retrier = retrier::start( *this, std::chrono::seconds( get_retry_sf_seconds() ) );
711  }
712 
713 
715  {
716  if( is_active() )
717  {
718  AC_LOG( ERROR, "Failed to trigger calibration: CAH is already active" );
719  throw wrong_api_call_sequence_exception( "CAH is already active" );
720  }
721  if( _retrier.get() || _recycler.get() )
722  {
723  AC_LOG( ERROR, "Bad inactive state: one of retrier or recycler is set!" );
724  throw std::runtime_error( "bad inactive state" );
725  }
726 
728  AC_LOG( DEBUG, "Calibration type is " << (type == calibration_type::MANUAL ? "MANUAL" : "AUTO") );
729 
730  try
731  {
733  }
734  catch( invalid_value_exception const & )
735  {
737  // Above throws invalid_value_exception, which we want: if calibration is triggered
738  // under bad conditions, we want the user to get this!
739  throw;
740  }
741 
742  _n_retries = 0;
743  _n_cycles = 1; // now active
745  AC_LOG( INFO, "Camera Accuracy Health check is now active (HUM temp is " << _temp << " dec C)" );
747  _next_trigger.reset(); // don't need a trigger any more
748  _temp_check.reset(); // nor a temperature check
751  {
752  AC_LOG( DEBUG, "Waiting for RGB stability before asking for special frame" );
753  _retrier = retrier::start( *this, std::chrono::seconds( get_retry_sf_seconds() + 1 ) );
754  }
755  else
756  {
757  AC_LOG( DEBUG, "Sending GET_SPECIAL_FRAME (cycle 1)" );
759  }
760  }
761 
762 
764  {
765  // With AC, we need a color sensor even when the user has not asked for one --
766  // otherwise we risk misalignment over time. We turn it on automatically!
767  try
768  {
770  if( ! color_sensor )
771  {
772  AC_LOG( ERROR, "No color sensor in device; cannot run AC?!" );
773  return;
774  }
775 
777  auto rgb_profile = depth_sensor.is_color_sensor_needed();
778  if( ! rgb_profile )
779  return; // error should have already been printed
780  //AC_LOG( DEBUG, "Picked profile: " << *rgb_profile );
781 
782  // If we just started the sensor, especially for AC, then we cannot simply take
783  // the first RGB frame we get: for various reasons, including auto exposure, the
784  // first frames we receive cannot be used (there's a "fade-in" effect). So we
785  // only enable frame capture after some time has passed (see set_color_frame):
788  = color_sensor->start_stream_for_calibration( { rgb_profile } );
789  }
790  catch( std::exception const & e )
791  {
792  AC_LOG( ERROR, "EXCEPTION caught: " << e.what() );
793  }
794  }
795 
796 
798  {
800 
801  // By using a thread we protect a case that tries to close a sensor from it's processing block callback and creates a deadlock.
802  std::thread([&]()
803  {
804  try
805  {
806  auto & color_sensor = *_dev.get_color_sensor();
807  color_sensor.stop_stream_for_calibration();
808  }
809  catch (std::exception& ex)
810  {
811  AC_LOG(ERROR, "caught exception in closing color sensor: " << ex.what());
812  }
813  catch (...)
814  {
815  AC_LOG(ERROR, "unknown exception in closing color sensor");
816  }
817  }).detach();
818 
819  }
820 
821 
823  {
824  if( ! is_active() )
825  {
826  AC_LOG( ERROR, "Special frame received while is_active() is false" );
827  return;
828  }
829 
830  // Notify of the special frame -- mostly for validation team so they know to expect a frame
831  // drop...
833 
834  if( _is_processing )
835  {
836  AC_LOG( ERROR, "already processing; ignoring special frame!" );
837  return;
838  }
839  auto irf = fs.get_infrared_frame();
840  if( ! irf )
841  {
842  AC_LOG( ERROR, "no IR frame found; ignoring special frame!" );
843  //call_back( RS2_CALIBRATION_FAILED );
844  return;
845  }
846  auto df = fs.get_depth_frame();
847  if( ! df )
848  {
849  AC_LOG( ERROR, "no depth frame found; ignoring special frame!" );
850  //call_back( RS2_CALIBRATION_FAILED );
851  return;
852  }
853 
854  _retrier.reset(); // No need to activate a retry if the following takes a bit of time!
855 
856  _sf = fs; // Assign right before the sync otherwise we may start() prematurely
857  _sf.keep();
858  std::lock_guard< std::mutex > lock( _mutex );
859  if( check_color_depth_sync() )
860  run_algo();
861  else
862  _retrier = retrier::start( *this, std::chrono::seconds( get_retry_sf_seconds() ) );
863  }
864 
865 
867  {
868  if( ! is_active() || _is_processing )
869  // No error message -- we expect to get new color frames while processing...
870  return;
872  {
873  // Wait at least a second before we deem the sensor stable enough
875  if( time < std::chrono::milliseconds( 1000 ) )
876  return;
877 
878  auto number = f.get_frame_number();
879  AC_LOG( DEBUG, "RGB frame #" << number << " is our first stable frame" );
881  {
882  AC_LOG( DEBUG,
883  " actual exposure= "
885  AC_LOG( DEBUG,
886  " backlight compensation= "
888  AC_LOG( DEBUG,
889  " brightness= "
891  AC_LOG( DEBUG,
892  " contrast= "
894  }
897  }
898 
899  _pcf = _cf;
900  _cf = f;
901  _cf.keep();
902  std::lock_guard< std::mutex > lock( _mutex );
903  if( check_color_depth_sync() )
904  run_algo();
905  }
906 
907 
909  {
910  // Only one thread is allowed to start(), and _is_processing is set within
911  // the mutex!
912  if( _is_processing )
913  return false;
914 
915  if( !_sf )
916  {
917  //std::cout << "-D- no special frame yet" << std::endl;
918  return false;
919  }
920  if( !_cf )
921  {
922  AC_LOG( DEBUG, "no color frame received; maybe color stream isn't on?" );
923  return false;
924  }
925  if( ! _pcf )
926  {
927  AC_LOG( DEBUG, "no prev color frame received" );
928  return false;
929  }
930  return true;
931  }
932 
934  const rs2::stream_profile & profile )
935  {
936  auto vp = profile.as< rs2::video_stream_profile >();
937  return dev.get_color_sensor()->get_raw_intrinsics(vp.width(), vp.height() );
938  }
939 
941  {
942  AC_LOG( DEBUG,
943  "Starting processing:"
944  << " color #" << _cf.get_frame_number() << " " << _cf.get_profile()
945  << " depth #" << _sf.get_frame_number() << ' ' << _sf.get_profile() );
947  _is_processing = true;
948  _retrier.reset();
949  if( _worker.joinable() )
950  {
951  AC_LOG( DEBUG, "Waiting for worker to join ..." );
952  _worker.join();
953  }
954  _worker = std::thread(
955  [&]() {
956  try
957  {
958  AC_LOG( DEBUG, "Calibration algo has started ..." );
960 
961  // We have to read the FW registers at the time of the special frame, but we
962  // cannot do it from set_special_frame() because it takes time and we should not
963  // hold up the thread that the frame callbacks are on!
964  float dsm_x_scale, dsm_y_scale, dsm_x_offset, dsm_y_offset;
967  {
968  auto hwm = _hwm.lock();
969  if( ! hwm )
970  throw std::runtime_error( "HW monitor is inaccessible - stopping algo" );
971 
972  ivcam2::read_fw_register( *hwm, &dsm_x_scale, 0xfffe3844 );
973  ivcam2::read_fw_register( *hwm, &dsm_y_scale, 0xfffe3830 );
974  ivcam2::read_fw_register( *hwm, &dsm_x_offset, 0xfffe3840 );
975  ivcam2::read_fw_register( *hwm, &dsm_y_offset, 0xfffe382c );
976 
977  ivcam2::read_fw_table( *hwm, cal_info.table_id, &cal_info );
978 
979  // If the above throw (and they can!) then we catch below and stop...
980 
981  try
982  {
983  thermal_table = _dev.get_color_sensor()->get_thermal_table();
984  }
985  catch( std::exception const & e )
986  {
987  AC_LOG( WARNING, std::string( to_string() << "Disabling thermal correction: " << e.what() << " [NO-THERMAL]" ));
988  }
989  }
990 
991  AC_LOG( DEBUG,
992  "dsm registers= x[" << AC_F_PREC << dsm_x_scale << ' ' << dsm_y_scale
993  << "] +[" << dsm_x_offset << ' ' << dsm_y_offset
994  << "]" );
996  cal_regs.EXTLdsmXscale = dsm_x_scale;
997  cal_regs.EXTLdsmYscale = dsm_y_scale;
998  cal_regs.EXTLdsmXoffset = dsm_x_offset;
999  cal_regs.EXTLdsmYoffset = dsm_y_offset;
1000 
1001  auto df = _sf.get_depth_frame();
1002  auto irf = _sf.get_infrared_frame();
1003 
1004  auto should_continue = [&]()
1005  {
1006  if( ! is_processing() )
1007  {
1008  AC_LOG( DEBUG, "Stopping algo: not processing any more" );
1009  throw std::runtime_error( "stopping algo: not processing any more" );
1010  }
1011  };
1014  settings.hum_temp = _temp;
1015  settings.digital_gain = _digital_gain;
1016  settings.receiver_gain = _receiver_gain;
1018  settings,
1019  df,
1020  irf,
1021  _cf,
1022  _pcf,
1024  cal_info,
1025  cal_regs,
1027  thermal_table,
1028  should_continue );
1029 
1030  std::string debug_dir = get_ac_logger().get_active_dir();
1031  if( ! debug_dir.empty() )
1032  algo.write_data_to( debug_dir );
1033 
1035  _to_profile = algo.get_to_profile();
1036 
1037  rs2_calibration_status status = RS2_CALIBRATION_FAILED; // assume fail until we get a success
1038 
1039  if( is_processing() ) // check if the device still exists
1040  {
1041  status = algo.optimize(
1042  [this]( rs2_calibration_status status ) { call_back( status ); });
1043  }
1044 
1045  // It's possible that, while algo was working, stop() was called. In this case,
1046  // we have to make sure that we notify of failure:
1047  if( ! is_processing() )
1048  {
1049  AC_LOG( DEBUG, "Algo finished (with " << status << "), but stop() was detected; notifying of failure..." );
1050  status = RS2_CALIBRATION_FAILED;
1051  }
1052 
1053  switch( status )
1054  {
1056  _extr = algo.get_extrinsics();
1057  _raw_intr = algo.get_raw_intrinsics();
1059  _dsm_params = algo.get_dsm_params();
1060  call_back( status ); // if this throws, we don't want to do the below:
1061  _last_temp = _temp;
1063  break;
1065  // This is the same as SUCCESSFUL, except there was no change because the
1066  // existing calibration is good enough. We notify and exit.
1067  call_back( status );
1068  break;
1069  case RS2_CALIBRATION_RETRY:
1070  // We want to trigger a special frame after a certain longer delay
1071  if( ++_n_cycles > 5 )
1072  {
1073  // ... but we've tried too many times
1074  AC_LOG( ERROR, "Too many retry cycles; quitting" );
1076  }
1077  else
1078  {
1079  AC_LOG( DEBUG, "Waiting for retry cycle " << _n_cycles << " ..." );
1080  bool const is_manual = _calibration_type == calibration_type::MANUAL;
1081  int n_seconds
1082  = env_var< int >( is_manual ? "RS2_AC_INVALID_RETRY_SECONDS_MANUAL"
1083  : "RS2_AC_INVALID_RETRY_SECONDS_AUTO",
1084  is_manual ? 2 : 60,
1085  []( int n ) { return n > 0; } );
1086  _recycler = retrier::start( *this, std::chrono::seconds( n_seconds ) );
1087  }
1088  break;
1090  // Report it and quit: this is a final status
1091  call_back( status );
1092  break;
1093  default:
1094  // All the rest of the codes are not end-states of the algo, so we don't expect
1095  // to get here!
1096  AC_LOG( ERROR,
1097  "Unexpected status '" << status << "' received from CAH algo; stopping!" );
1099  break;
1100  }
1101  }
1102  catch( std::exception & e )
1103  {
1104  AC_LOG( ERROR, "EXCEPTION in calibration algo: " << e.what() );
1105  try
1106  {
1108  }
1109  catch( std::exception & e )
1110  {
1111  AC_LOG( ERROR, "EXCEPTION in FAILED callback: " << e.what() );
1112  }
1113  catch( ... )
1114  {
1115  AC_LOG( ERROR, "EXCEPTION in FAILED callback!" );
1116  }
1117  }
1118  catch( ... )
1119  {
1120  AC_LOG( ERROR, "Unknown EXCEPTION in calibration algo!!!" );
1121  try
1122  {
1124  }
1125  catch( std::exception & e )
1126  {
1127  AC_LOG( ERROR, "EXCEPTION in FAILED callback: " << e.what() );
1128  }
1129  catch( ... )
1130  {
1131  AC_LOG( ERROR, "EXCEPTION in FAILED callback!" );
1132  }
1133  }
1134  _is_processing = false; // to avoid debug msg in reset()
1135  reset();
1136  switch( _last_status_sent )
1137  {
1142  break;
1143  }
1144  } );
1145  }
1146 
1147 
1149  {
1150  if( ! is_active() )
1151  return;
1152  if( is_processing() )
1153  {
1154  reset();
1155  // Wait until we're out of run_algo() -- until then, we're active!
1156  }
1157  else
1158  {
1161  reset();
1162  _retrier.reset();
1163  _recycler.reset();
1165  }
1166  }
1167 
1168 
1170  {
1171  if( is_active() )
1172  {
1173  // We get here when we've reached some final state (failed/successful)
1175  AC_LOG( WARNING, "Camera Accuracy Health has finished unsuccessfully" );
1176  else
1177  AC_LOG( INFO, "Camera Accuracy Health has finished" );
1178  set_not_active();
1179  }
1180 
1182  }
1183 
1184 
1186  {
1187  _n_cycles = 0;
1189  }
1190 
1191 
1193  {
1194  // Trigger the next CAH -- but only if we're "on", meaning this wasn't a manual calibration
1195  if( ! auto_calibration_is_on() )
1196  {
1197  AC_LOG( DEBUG, "Calibration mechanism is not on; not scheduling next calibration" );
1198  return;
1199  }
1200 
1203  }
1204 
1205  void ac_trigger::schedule_next_time_trigger( std::chrono::seconds n_seconds )
1206  {
1207  if( ! n_seconds.count() )
1208  {
1209  n_seconds = get_trigger_seconds();
1210  if (!n_seconds.count())
1211  {
1212  AC_LOG(DEBUG, "RS2_AC_TRIGGER_SECONDS is 0; no time trigger");
1213  return;
1214  }
1215  }
1216 
1217  // If there's already a trigger, this will simply override it
1218  _next_trigger = retrier::start< next_trigger >( *this, n_seconds );
1219  }
1220 
1222  {
1223  // If no _last_temp --> first calibration! We want to keep checking every minute
1224  // until temperature is within proper conditions...
1225  if( get_temp_diff_trigger() || ! _last_temp )
1226  {
1227  //AC_LOG( DEBUG, "Last HUM temperature= " << _last_temp );
1228  _temp_check = retrier::start< temp_check >( *this, std::chrono::seconds( 60 ) );
1229  }
1230  else
1231  {
1232  AC_LOG( DEBUG, "RS2_AC_TEMP_DIFF is 0; no temperature change trigger" );
1233  }
1234  }
1235 
1236 
1238  {
1240  }
1241 
1242 
1244  {
1245  // Make sure we're still streaming
1246  bool is_streaming = false;
1247  try
1248  {
1249  is_streaming = _dev.get_depth_sensor().is_streaming();
1250  }
1251  catch( std::exception const & e )
1252  {
1253  AC_LOG( ERROR, "EXCEPTION caught: " << e.what() );
1254  }
1255  if( ! is_streaming )
1256  {
1257  AC_LOG( ERROR, "Not streaming; stopping" );
1258  stop();
1259  throw wrong_api_call_sequence_exception( "not streaming" );
1260  }
1261 
1262  std::string invalid_reason;
1263 
1264  auto alt_ir_is_on = false;
1265  try
1266  {
1267  auto & depth_sensor = _dev.get_depth_sensor();
1268  alt_ir_is_on = depth_sensor.supports_option( RS2_OPTION_ALTERNATE_IR )
1269  && depth_sensor.get_option( RS2_OPTION_ALTERNATE_IR ).query() == 1.f;
1270  }
1271  catch( std::exception const & e )
1272  {
1273  AC_LOG( DEBUG,
1274  std::string( to_string() << "Error while checking alternate IR option: " << e.what() ) );
1275  }
1276  if( alt_ir_is_on )
1277  {
1278  if( ! invalid_reason.empty() )
1279  invalid_reason += ", ";
1280  invalid_reason += to_string() << "alternate IR is on";
1281  }
1282 
1283  _temp = read_temperature();
1284 
1285  auto thermal_table_valid = true;
1286  try
1287  {
1289  }
1290  catch( std::exception const & e )
1291  {
1292  AC_LOG( DEBUG, std::string( to_string() << "Disabling thermal correction: " << e.what() << " [NO-THERMAL]" ));
1293  thermal_table_valid = false;
1294  }
1295 
1296  if( ! thermal_table_valid )
1297  {
1298  if( _temp < 32. )
1299  {
1300  // If from some reason there is no thermal_table or its not valid
1301  // Temperature must be within range or algo may not work right
1302  if( ! invalid_reason.empty() )
1303  invalid_reason += ", ";
1304  invalid_reason += to_string() << "temperature (" << _temp << ") too low (<32)";
1305  }
1306  else if( _temp > 46. )
1307  {
1308  if( ! invalid_reason.empty() )
1309  invalid_reason += ", ";
1310  invalid_reason += to_string() << "temperature (" << _temp << ") too high (>46)";
1311  }
1312  }
1313 
1314 
1315  // Algo was written with specific receiver gain (APD) in mind, depending on
1316  // the FW preset (ambient light)
1317  auto & depth_sensor = _dev.get_depth_sensor();
1318  auto & digital_gain = depth_sensor.get_option(RS2_OPTION_DIGITAL_GAIN);
1319  float raw_digital_gain = digital_gain.query();
1320  auto & apd = depth_sensor.get_option( RS2_OPTION_AVALANCHE_PHOTO_DIODE );
1321  float raw_apd = apd.query();
1322  _receiver_gain = int( raw_apd );
1323  _digital_gain = ( rs2_digital_gain ) int(raw_digital_gain);
1324  switch(_digital_gain)
1325  {
1326  case RS2_DIGITAL_GAIN_LOW:
1327  if( _receiver_gain != 18 )
1328  {
1329  if( ! invalid_reason.empty() )
1330  invalid_reason += ", ";
1331  invalid_reason += to_string()
1332  << "receiver gain(" << raw_apd << ") of 18 is expected with low digital gain(SHORT)";
1333  }
1334  break;
1335 
1336  case RS2_DIGITAL_GAIN_HIGH:
1337  if( _receiver_gain != 9 )
1338  {
1339  if( ! invalid_reason.empty() )
1340  invalid_reason += ", ";
1341  invalid_reason += to_string()
1342  << "receiver gain(" << raw_apd << ") of 9 is expected with high digital gain(LONG)";
1343  }
1344  break;
1345 
1346  default:
1347  if( ! invalid_reason.empty() )
1348  invalid_reason += ", ";
1349  invalid_reason += to_string() << "invalid (" << raw_digital_gain << ") digital gain preset";
1350  break;
1351  }
1352 
1353  if( ! invalid_reason.empty() )
1354  {
1355  // This can and will happen every minute (from the temp check), therefore not an error...
1356  AC_LOG( DEBUG, "Invalid conditions for CAH: " << invalid_reason );
1357  if( ! env_var< bool >( "RS2_AC_DISABLE_CONDITIONS", false ) )
1358  throw invalid_value_exception( invalid_reason );
1359  AC_LOG( DEBUG, "RS2_AC_DISABLE_CONDITIONS is on; continuing anyway" );
1360  }
1361  }
1362 
1364  {
1365  try
1366  {
1367  option & o
1369  if( o.query() != float( RS2_CAH_TRIGGER_AUTO ) )
1370  {
1371  // auto trigger is turned off
1372  AC_LOG( DEBUG, "Turned off -- no trigger set" );
1373  return;
1374  }
1375  }
1376  catch( std::exception const & e )
1377  {
1378  AC_LOG( ERROR, "EXCEPTION caught in access to device: " << e.what() );
1379  return;
1380  }
1381 
1382  _start();
1383  }
1384 
1386  {
1387  if( auto_calibration_is_on() )
1388  throw wrong_api_call_sequence_exception( "CAH is already active" );
1389 
1390  if( ! is_auto_trigger_possible() )
1391  {
1392  AC_LOG( DEBUG, "Auto trigger is disabled in environment" );
1393  return; // no auto trigger
1394  }
1395 
1396  _is_on = true;
1397 
1398  // If we are already active then we don't need to do anything: another calibration will be
1399  // triggered automatically at the end of the current one
1400  if( is_active() )
1401  {
1402  return;
1403  }
1404 
1405  // Note: we arbitrarily choose the time before CAH starts at 10 second -- enough time to
1406  // make sure the user isn't going to fiddle with color sensor activity too much, because
1407  // if color is off then CAH will automatically turn it on!
1408  schedule_next_time_trigger( std::chrono::seconds( 10 ) );
1409  }
1410 
1412  {
1413  _is_on = false;
1414  if (is_active())
1415  {
1417  }
1418  else
1419  {
1420  if (_next_trigger)
1421  {
1422  AC_LOG(DEBUG, "Cancelling next time trigger");
1423  _next_trigger.reset();
1424  }
1425 
1426  if (_temp_check)
1427  {
1428  AC_LOG(DEBUG, "Cancelling next temp trigger");
1429  _temp_check.reset();
1430  }
1431  }
1432  }
1433 
1435  {
1436  _sf = rs2::frame{};
1437  _cf = rs2::frame{};;
1438  _pcf = rs2::frame{};
1439 
1441  if( _is_processing )
1442  {
1443  _is_processing = false;
1444  AC_LOG( DEBUG, "Algo is processing; signalling stop" );
1445  }
1446  }
1447 
1448 
1450  std::shared_ptr< ac_trigger > autocal
1451  )
1452  : generic_processing_block( "Auto Calibration (depth)" )
1453  , _autocal{ autocal }
1454  {
1455  }
1456 
1457 
1458  static bool is_special_frame( rs2::depth_frame const& f )
1459  {
1460  if( !f )
1461  return false;
1462 
1464  {
1465  // We specified 0x5F (SF = Special Frame) when we asked for the SPECIAL_FRAME
1467  return 0x5F == mode;
1468  }
1469 
1470  // When the frame doesn't support metadata, we have to look at its
1471  // contents: we take the first frame that has 100% fill rate, i.e.
1472  // has no pixels with 0 in them...
1473  uint16_t const * pd = reinterpret_cast<const uint16_t *>(f.get_data());
1474  for( size_t x = f.get_data_size() / sizeof( *pd ); x--; ++pd )
1475  {
1476  if( !*pd )
1477  return false;
1478  }
1479  AC_LOG( DEBUG, "frame " << f.get_frame_number() << " has no metadata but 100% fill rate -> assuming special frame" );
1480  return true; // None zero, assume special frame...
1481  }
1482 
1484  const rs2::frame & f )
1485  {
1486  // CAH can be triggered manually, too, so we do NOT check whether the option is on!
1487  auto fs = f.as< rs2::frameset >();
1488  auto autocal = _autocal.lock();
1489  if( fs )
1490  {
1491  auto df = fs.get_depth_frame();
1492  if( autocal && autocal->is_expecting_special_frame() && is_special_frame( df ) )
1493  {
1494  AC_LOG( DEBUG, "Depth frame #" << f.get_frame_number() << " is our special frame" );
1495  autocal->set_special_frame( f );
1496  }
1497  // Disregard framesets: we'll get those broken down into individual frames by generic_processing_block's on_frame
1498  return rs2::frame{};
1499  }
1500 
1501  if( autocal && autocal->is_expecting_special_frame() && is_special_frame( f.as< rs2::depth_frame >() ) )
1502  // We don't want the user getting this frame!
1503  return rs2::frame{};
1504 
1505  return f;
1506  }
1507 
1508 
1510  {
1511  return true;
1512  }
1513 
1514 
1516  const rs2::frame_source & source, rs2::frame input, std::vector< rs2::frame > results )
1517  {
1518  // The default prepare_output() will send the input back as the frame if the results are empty
1519  if( results.empty() )
1520  return rs2::frame{};
1521 
1522  return source.allocate_composite_frame( results );
1523  }
1524 
1525 
1527  std::shared_ptr< ac_trigger > autocal
1528  )
1529  : generic_processing_block( "Auto Calibration (color)" )
1530  , _autocal{ autocal }
1531  {
1532  }
1533 
1534 
1536  {
1537  // CAH can be triggered manually, too, so we do NOT check whether the option is on!
1538 
1539  // Disregard framesets: we'll get those broken down into individual frames by generic_processing_block's on_frame
1540  if( f.is< rs2::frameset >() )
1541  return rs2::frame{};
1542 
1543  auto autocal = _autocal.lock();
1544  if( autocal )
1545  // We record each and every color frame
1546  autocal->set_color_frame( f );
1547 
1548  // Return the frame as is!
1549  return f;
1550  }
1551 
1552 
1554  {
1555  return true;
1556  }
1557 
1558 
1559 } // namespace ivcam2
1560 } // namespace librealsense
rs2::frame prepare_output(const rs2::frame_source &source, rs2::frame input, std::vector< rs2::frame > results) override
static const textual_icon lock
Definition: model-views.h:218
std::vector< callback > _callbacks
Definition: ac-trigger.h:211
const char * rs2_format_to_string(rs2_format format)
Definition: rs.cpp:1263
std::shared_ptr< temp_check > _temp_check
Definition: ac-trigger.h:59
static std::ostream & operator<<(std::ostream &os, stream_profile const &sp)
Definition: ac-trigger.cpp:152
temp_check(ac_trigger &ac, const char *name)
Definition: ac-trigger.cpp:393
static int get_retry_sf_seconds()
Definition: ac-trigger.cpp:128
std::function< void(const option &)> _record_action
Definition: ac-trigger.h:136
GLenum GLuint GLenum severity
void trigger_calibration(calibration_type type)
Definition: ac-trigger.cpp:714
GLuint const GLchar * name
std::weak_ptr< ac_trigger > _autocal
Definition: ac-trigger.h:123
bool _is_set
Definition: ac-trigger.cpp:77
GLdouble s
rs2_dsm_params const & get_dsm_params() const
GLfloat GLfloat p
Definition: glext.h:12687
bool should_process(const rs2::frame &frame) override
reset_option(std::shared_ptr< ac_trigger > const &autocal)
Definition: ac-trigger.cpp:203
rs2_extrinsics const & get_extrinsics() const
void log_to_callback(rs2_log_severity min_severity, log_callback_ptr callback)
Definition: log.cpp:54
rs2_metadata_type get_frame_metadata(rs2_frame_metadata_value frame_metadata) const
Definition: rs_frame.hpp:497
depth_processing_block(std::shared_ptr< ac_trigger > autocal)
virtual l500_color_sensor * get_color_sensor()=0
GLsizei const GLchar *const * path
Definition: glext.h:4276
GLfloat value
bool get_id(DEVINST devinst, std::string *p_out_str)
stream_profile get_profile() const
Definition: rs_frame.hpp:557
next_trigger(ac_trigger &ac, const char *name)
Definition: ac-trigger.cpp:367
static double get_temp_diff_trigger()
Definition: ac-trigger.cpp:134
void convert(rs2_format source, std::string &target)
const void * get_data() const
Definition: rs_frame.hpp:545
bool supports_frame_metadata(rs2_frame_metadata_value frame_metadata) const
Definition: rs_frame.hpp:509
unsigned short uint16_t
Definition: stdint.h:79
Definition: cah-model.h:10
GLsizei const GLchar *const * string
ac_trigger(l500_device &dev, std::shared_ptr< hw_monitor > hwm)
Definition: ac-trigger.cpp:599
static bool is_auto_trigger_possible()
Definition: ac-trigger.cpp:173
calibration_type _calibration_type
Definition: ac-trigger.h:146
GLdouble n
Definition: glext.h:1966
e
Definition: rmse.py:177
option & get_option(rs2_option id) override
Definition: options.h:58
virtual float query() const =0
rs2_intrinsics get_raw_intrinsics(uint32_t width, uint32_t height) const
Definition: l500-color.cpp:229
GLenum GLuint id
bool auto_calibration_is_on() const
Definition: ac-trigger.h:170
status
Defines return codes that SDK interfaces use. Negative values indicate errors, a zero value indicates...
rs2::frame process_frame(const rs2::frame_source &source, const rs2::frame &f) override
depth_frame get_depth_frame() const
Definition: rs_frame.hpp:1006
GLenum GLuint GLenum GLsizei const GLchar * buf
static std::string convert(std::string const &s)
Definition: ac-trigger.cpp:28
env_var(char const *name, T default_value, std::function< bool(T) > checker=nullptr)
Definition: ac-trigger.cpp:81
void set(float value) override
Definition: option.h:332
std::atomic_bool _is_processing
Definition: ac-trigger.h:36
GLdouble f
algo::thermal_loop::l500::thermal_calibration_table get_thermal_table() const
Definition: l500-color.cpp:414
bool is() const
Definition: rs_frame.hpp:570
GLenum mode
rs2_intrinsics const & get_raw_intrinsics() const
static std::string _prefix(std::string const &name, unsigned id)
Definition: ac-trigger.cpp:307
std::vector< uint16_t > _last_yuy_data
Definition: ac-trigger.h:47
static std::string now_string(char const *format_string="%T")
Definition: ac-trigger.cpp:117
static std::shared_ptr< T > start(ac_trigger &trigger, std::chrono::seconds n_seconds, const char *name=nullptr)
Definition: ac-trigger.cpp:328
void retry(ac_trigger &trigger) override
Definition: ac-trigger.cpp:399
retrier(ac_trigger &ac, char const *name)
Definition: ac-trigger.cpp:295
std::ostream & cout()
rs2_calibration_status optimize(std::function< void(rs2_calibration_status)> call_back=nullptr)
bool should_process(const rs2::frame &frame) override
GLdouble GLdouble r
static bool is_special_frame(rs2::depth_frame const &f)
GLdouble x
rs2_calibration_status
Definition: rs_device.h:356
l500_depth_sensor & get_depth_sensor()
frame allocate_composite_frame(std::vector< frame > frames) const
std::shared_ptr< next_trigger > _next_trigger
Definition: ac-trigger.h:54
void on_log(rs2_log_severity severity, rs2_log_message const &msg) noexceptoverride
Definition: ac-trigger.cpp:559
struct rs2_log_message rs2_log_message
Definition: rs_types.h:259
std::shared_ptr< ac_trigger > get_ac() const
Definition: ac-trigger.cpp:304
void set_color_frame(rs2::frame const &)
Definition: ac-trigger.cpp:866
void keep()
Definition: rs_frame.hpp:437
float query() const override
Definition: option.h:238
static void write_out(std::string const &s)
Definition: ac-trigger.cpp:582
bool is_streaming() const override
Definition: sensor.cpp:1619
#define AC_LOG(TYPE, MSG)
rs2_calibration_status _last_status_sent
Definition: ac-trigger.h:52
stream_profile_interface * get_from_profile() const
stream_profile_interface * _to_profile
Definition: ac-trigger.h:46
librealsense::stream_profile_interface * profile
Definition: context.h:34
bool is_set() const
Definition: ac-trigger.cpp:107
std::string const & get_active_dir() const
Definition: ac-trigger.cpp:530
GLenum GLenum GLenum input
Definition: glext.h:10805
T value() const
Definition: ac-trigger.cpp:108
void schedule_next_time_trigger(std::chrono::seconds n_seconds=std::chrono::seconds(0))
GLenum type
void set_special_frame(rs2::frameset const &)
Definition: ac-trigger.cpp:822
const rs2_stream_profile * get() const
Definition: rs_frame.hpp:137
static bool is_auto_trigger_default()
Definition: ac-trigger.cpp:181
#define RS2_API_FULL_VERSION_STR
Definition: rs.h:44
static bool convert(std::string const &s)
Definition: ac-trigger.cpp:52
GLint GLsizei count
rs2_intrinsics read_intrinsics_from_camera(l500_device &dev, const rs2::stream_profile &profile)
Definition: ac-trigger.cpp:933
void retry(ac_trigger &trigger) override
Definition: ac-trigger.cpp:373
typename::boost::move_detail::remove_reference< T >::type && move(T &&t) BOOST_NOEXCEPT
Video stream intrinsics.
Definition: rs_types.h:58
rs2_digital_gain _digital_gain
Definition: ac-trigger.h:27
GLsizei GLsizei GLchar * source
std::vector< algo::depth_to_rgb_calibration::yuy_t > & get_last_successful_frame_data()
rs2_digital_gain
digital gain for RS2_OPTION_DIGITAL_GAIN option.
Definition: rs_option.h:183
void read_fw_table(hw_monitor &hwm, int table_id, T *ptable, table_header *pheader=nullptr, std::function< void() > init=nullptr)
Definition: l500-private.h:109
stream_profile_interface * get_to_profile() const
const int get_data_size() const
Definition: rs_frame.hpp:533
std::shared_ptr< retrier > _retrier
Definition: ac-trigger.h:49
#define NULL
Definition: tinycthread.c:47
video_frame get_infrared_frame(const size_t index=0) const
Definition: rs_frame.hpp:1032
void call_back(rs2_calibration_status status)
Definition: ac-trigger.cpp:627
#define INFO(msg)
Definition: catch.hpp:17429
static std::chrono::seconds get_trigger_seconds()
Definition: ac-trigger.cpp:140
stream_profile_interface * _from_profile
Definition: ac-trigger.h:45
static int convert(std::string const &s)
Definition: ac-trigger.cpp:37
std::weak_ptr< hw_monitor > _hwm
Definition: ac-trigger.h:31
virtual void set(float value) override
Definition: ac-trigger.cpp:269
void read_fw_register(hw_monitor &hwm, T *preg, int const baseline_address)
Definition: l500-private.h:178
unsigned long long get_frame_number() const
Definition: rs_frame.hpp:521
rs2_log_severity
Severity of the librealsense logger.
Definition: rs_types.h:153
std::shared_ptr< retrier > _recycler
Definition: ac-trigger.h:51
GLdouble v
rs2_intrinsics const & get_thermal_intrinsics() const
std::weak_ptr< ac_trigger > _ac
Definition: ac-trigger.cpp:290
static void add_dir_sep(std::string &path)
Definition: ac-trigger.cpp:479
ivcam2::extended_temperatures get_temperatures() const
virtual void set(float value) override
Definition: ac-trigger.cpp:209
std::chrono::high_resolution_clock::time_point _rgb_sensor_start
Definition: ac-trigger.h:62
rs2::frame process_frame(const rs2::frame_source &source, const rs2::frame &f) override
color_processing_block(std::shared_ptr< ac_trigger > autocal)
virtual void retry(ac_trigger &trigger)
Definition: ac-trigger.cpp:316
T as() const
Definition: rs_frame.hpp:580
std::string to_string(T value)


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:45:06