392 config( m_fgThreadPrio,
"framegrabber.threadPrio" );
393 config( m_fgCpuset,
"framegrabber.cpuset" );
394 if( m_shmimName ==
"" )
395 m_shmimName = derived().configName();
396 config( m_shmimName,
"framegrabber.shmimName" );
398 config( m_circBuffLength,
"framegrabber.circBuffLength" );
400 if( m_circBuffLength < 1 )
402 m_circBuffLength = 1;
403 derivedT::template log<text_log>(
"circBuffLength set to 1" );
406 config( m_latencyCircBuffMaxTime,
"framegrabber.latencyTime" );
407 if( m_latencyCircBuffMaxTime < 0 )
409 m_latencyCircBuffMaxTime = 0;
410 derivedT::template log<text_log>(
"latencyTime set to 0 (off)" );
413 config( m_latencyCircBuffMaxLength,
"framegrabber.latencySize" );
415 if( derivedT::c_frameGrabber_flippable )
417 std::string flip =
"flipNone";
419 config( flip,
"framegrabber.defaultFlip" );
421 if( flip ==
"flipNone" )
423 m_defaultFlip = fgFlipNone;
425 else if( flip ==
"flipUD" )
427 m_defaultFlip = fgFlipUD;
429 else if( flip ==
"flipLR" )
431 m_defaultFlip = fgFlipLR;
433 else if( flip ==
"flipUDLR" )
435 m_defaultFlip = fgFlipUDLR;
439 derivedT::template log<text_log>( { std::string(
"invalid framegrabber flip"
440 "specification (" ) +
441 flip +
"), setting flipNone" },
442 logPrio::LOG_ERROR );
444 m_defaultFlip = fgFlipNone;
456 m_indiP_shmimName = pcf::IndiProperty( pcf::IndiProperty::Text );
457 m_indiP_shmimName.setDevice( derived().configName() );
458 m_indiP_shmimName.setName(
"fg_shmimName" );
459 m_indiP_shmimName.setPerm( pcf::IndiProperty::ReadOnly );
460 m_indiP_shmimName.setState( pcf::IndiProperty::Idle );
461 m_indiP_shmimName.add( pcf::IndiElement(
"name" ) );
462 m_indiP_shmimName[
"name"] = m_shmimName;
464 if( derived().registerIndiPropertyNew( m_indiP_shmimName,
nullptr ) < 0 )
466#ifndef FRAMEGRABBER_TEST_NOLOG
467 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
473 m_indiP_frameSize = pcf::IndiProperty( pcf::IndiProperty::Number );
474 m_indiP_frameSize.setDevice( derived().configName() );
475 m_indiP_frameSize.setName(
"fg_frameSize" );
476 m_indiP_frameSize.setPerm( pcf::IndiProperty::ReadOnly );
477 m_indiP_frameSize.setState( pcf::IndiProperty::Idle );
478 m_indiP_frameSize.add( pcf::IndiElement(
"width" ) );
479 m_indiP_frameSize[
"width"] = 0;
480 m_indiP_frameSize.add( pcf::IndiElement(
"height" ) );
481 m_indiP_frameSize[
"height"] = 0;
483 if( derived().registerIndiPropertyNew( m_indiP_frameSize,
nullptr ) < 0 )
485#ifndef FRAMEGRABBER_TEST_NOLOG
486 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
492 derived().createROIndiNumber( m_indiP_timing,
"fg_timing" );
493 m_indiP_timing.add( pcf::IndiElement(
"acq_fps" ) );
494 m_indiP_timing.add( pcf::IndiElement(
"acq_min" ) );
495 m_indiP_timing.add( pcf::IndiElement(
"acq_max" ) );
496 m_indiP_timing.add( pcf::IndiElement(
"acq_jitter" ) );
497 m_indiP_timing.add( pcf::IndiElement(
"write_fps" ) );
498 m_indiP_timing.add( pcf::IndiElement(
"write_min" ) );
499 m_indiP_timing.add( pcf::IndiElement(
"write_max" ) );
500 m_indiP_timing.add( pcf::IndiElement(
"write_jitter" ) );
501 m_indiP_timing.add( pcf::IndiElement(
"delta_aw" ) );
502 m_indiP_timing.add( pcf::IndiElement(
"delta_aw_jitter" ) );
504 if( derived().registerIndiPropertyReadOnly( m_indiP_timing ) < 0 )
506#ifndef STDCAMERA_TEST_NOLOG
507 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
513 if( derived().threadStart( m_fgThread,
521 fgThreadStart ) < 0 )
523 derivedT::template log<software_error, -1>( { __FILE__, __LINE__ } );
534 if( pthread_tryjoin_np( m_fgThread.native_handle(), 0 ) == 0 )
536 derivedT::template log<software_error>( { __FILE__, __LINE__,
"framegrabber thread has exited" } );
545 if( m_atimes.size() >= m_atimes.maxEntries() )
548 cbIndexT latTime = m_latencyCircBuffMaxTime * m_cbFPS;
549 if( latTime >= m_atimes.maxEntries() )
551 latTime = m_atimes.maxEntries() - 1;
554 m_atimesD.resize( latTime - 1 );
555 m_wtimesD.resize( latTime - 1 );
556 m_watimesD.resize( latTime - 1 );
558 cbIndexT refEntry = m_atimes.latest();
560 if( refEntry >= latTime )
566 refEntry = m_atimes.maxEntries() + refEntry - latTime;
569 timespec ts = m_atimes.at( refEntry, 0 );
570 double a0 = ts.tv_sec + ( (double)ts.tv_nsec ) / 1e9;
572 ts = m_wtimes.at( refEntry, 0 );
573 double w0 = ts.tv_sec + ( (double)ts.tv_nsec ) / 1e9;
580 for(
size_t n = 1; n <= m_atimesD.size(); ++n )
582 ts = m_atimes.at( refEntry, n );
583 double a = ts.tv_sec + ( (double)ts.tv_nsec ) / 1e9;
585 ts = m_wtimes.at( refEntry, n );
586 double w = ts.tv_sec + ( (double)ts.tv_nsec ) / 1e9;
588 m_atimesD[n - 1] =
a - a0;
589 m_wtimesD[n - 1] = w - w0;
590 m_watimesD[n - 1] = w -
a;
594 if( m_atimesD[n - 1] < mina )
596 mina = m_atimesD[n - 1];
599 if( m_atimesD[n - 1] > maxa )
601 maxa = m_atimesD[n - 1];
604 if( m_wtimesD[n - 1] < minw )
606 minw = m_wtimesD[n - 1];
609 if( m_wtimesD[n - 1] > maxw )
611 maxw = m_wtimesD[n - 1];
614 if( m_wtimesD[n - 1] < 0 )
616 std::cerr <<
"negative wtime: " << m_wtimesD[n - 1] <<
' ' << n <<
' ' << m_atimesD.size()
617 <<
' ' << refEntry <<
' ' << m_atimes.maxEntries() <<
' ' << latTime <<
'\n';
618 return derivedT::template log<software_error, 0>(
619 { __FILE__, __LINE__,
"negative write time. latency circ buff is not long enought" } );
623 m_mna = mx::math::vectorMean( m_atimesD );
624 m_vara = mx::math::vectorVariance( m_atimesD, m_mna );
628 m_mnw = mx::math::vectorMean( m_wtimesD );
629 m_varw = mx::math::vectorVariance( m_wtimesD, m_mnw );
633 m_mnwa = mx::math::vectorMean( m_watimesD );
634 m_varwa = mx::math::vectorVariance( m_watimesD, m_mnwa );
666 catch(
const std::exception &e )
668 std::cerr << e.what() <<
'\n';
718 m_cbFPS = derived().fps();
720 if( m_latencyCircBuffMaxLength == 0 || m_latencyCircBuffMaxTime == 0 || m_cbFPS <= 0 )
722 m_atimes.maxEntries( 0 );
723 m_wtimes.maxEntries( 0 );
733 std::cerr <<
"Circ Buff setup: " << m_latencyCircBuffMaxTime <<
' ' << m_cbFPS <<
' ';
734 cbIndexT cbSz = 2 * m_latencyCircBuffMaxTime * m_cbFPS;
735 if( cbSz > m_latencyCircBuffMaxLength )
737 cbSz = m_latencyCircBuffMaxLength;
744 std::cerr << cbSz <<
'\n';
746 m_atimes.maxEntries( cbSz );
747 m_wtimes.maxEntries( cbSz );
763 m_fgThreadID = syscall( SYS_gettid );
768 while( m_fgThreadInit ==
true && derived().shutdown() == 0 )
773 uint32_t imsize[3] = { 0, 0, 0 };
774 std::string shmimName;
776 while( derived().shutdown() == 0 )
779 while( !derived().shutdown() &&
781 derived().powerState() <= 0 ) )
786 if( derived().shutdown() )
792 if( derived().configureAcquisition() < 0 )
797 m_typeSize = ImageStreamIO_typesize( m_dataType );
799 if( configCircBuffs() < 0 )
801 derivedT::template log<software_error>( { __FILE__, __LINE__,
"error configuring latency circ. buffs" } );
806 if( m_shmimName ==
"" )
807 m_shmimName = derived().configName();
809 if( m_width != imsize[0] || m_height != imsize[1] ||
static_cast<uint32_t
>( m_circBuffLength ) != imsize[2] ||
810 m_shmimName != shmimName || m_imageStream ==
nullptr )
812 if( m_imageStream !=
nullptr )
814 ImageStreamIO_destroyIm( m_imageStream );
815 free( m_imageStream );
818 m_imageStream =
reinterpret_cast<IMAGE *
>( malloc(
sizeof( IMAGE ) ) );
821 imsize[1] = m_height;
822 imsize[2] = m_circBuffLength;
823 shmimName = m_shmimName;
825 std::cerr <<
"Creating: " << m_shmimName <<
" " << m_width <<
" " << m_height <<
" " << m_circBuffLength
828 ImageStreamIO_createIm_gpu( m_imageStream,
837 CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
840 m_imageStream->md->cnt1 = m_circBuffLength - 1;
846 if( derived().startAcquisition() < 0 )
851 uint64_t next_cnt1 = 0;
852 char *next_dest =
reinterpret_cast<char *
>( m_imageStream->array.raw );
853 timespec *next_wtimearr = &m_imageStream->writetimearray[0];
854 timespec *next_atimearr = &m_imageStream->atimearray[0];
855 uint64_t *next_cntarr = &m_imageStream->cntarray[0];
858 while( !derived().shutdown() && !m_reconfig && derived().powerState() > 0 )
863 int isValid = derived().acquireAndCheckValid();
877 m_imageStream->md->write = 1;
882 if( derived().loadImageIntoStream( next_dest ) < 0 )
889 if( clock_gettime( CLOCK_REALTIME, &m_imageStream->md->writetime ) < 0 )
891 derivedT::template log<software_critical>( { __FILE__, __LINE__, errno, 0,
"clock_gettime" } );
895 m_imageStream->md->atime = m_currImageTimestamp;
898 m_imageStream->md->cnt1 = next_cnt1;
901 m_imageStream->md->cnt0++;
903 *next_wtimearr = m_imageStream->md->writetime;
904 *next_atimearr = m_currImageTimestamp;
905 *next_cntarr = m_imageStream->md->cnt0;
908 m_imageStream->md->write = 0;
909 ImageStreamIO_sempost( m_imageStream, -1 );
912 if( m_atimes.maxEntries() > 0 )
914 m_atimes.nextEntry( m_imageStream->md->atime );
915 m_wtimes.nextEntry( m_imageStream->md->writetime );
919 next_cnt1 = m_imageStream->md->cnt1 + 1;
920 if( next_cnt1 >= m_circBuffLength )
926 reinterpret_cast<char *
>( m_imageStream->array.raw ) + next_cnt1 * m_width * m_height * m_typeSize;
927 next_wtimearr = &m_imageStream->writetimearray[next_cnt1];
928 next_atimearr = &m_imageStream->atimearray[next_cnt1];
929 next_cntarr = &m_imageStream->cntarray[next_cnt1];
932 m_dummy_c = next_dest[0];
933 m_dummy_ts.tv_sec = next_wtimearr[0].tv_sec + next_atimearr[0].tv_sec;
934 m_dummy_cnt = next_cntarr[0];
936 if( m_cbFPS != derived().fps() )
938 if( configCircBuffs() < 0 )
940 derivedT::template log<software_error>(
941 { __FILE__, __LINE__,
"error configuring latency circ. buffs" } );
946 if( m_reconfig && !derived().shutdown() )
948 derived().reconfig();
953 if( m_imageStream !=
nullptr )
955 ImageStreamIO_destroyIm( m_imageStream );
956 free( m_imageStream );
957 m_imageStream =
nullptr;
964 if( !derivedT::c_frameGrabber_flippable )
966 return memcpy( dest, src, width * height * szof );
970 switch( m_defaultFlip )
973 return mx::improc::imcpy( dest, src, width, height, szof );
975 return mx::improc::imcpy_flipUD( dest, src, width, height, szof );
977 return mx::improc::imcpy_flipLR( dest, src, width, height, szof );
979 return mx::improc::imcpy_flipUDLR( dest, src, width, height, szof );
989 if( !derived().m_indiDriver )
1003 indi::updateIfChanged<double>(
1014 "delta_aw_jitter" },
1015 { fpsa, m_mina, m_maxa, sqrt( m_vara ), fpsw, m_minw, m_maxw, sqrt( m_varw ), m_mnwa, sqrt( m_varwa ) },
1016 derived().m_indiDriver );