394 config( m_fgThreadPrio,
"framegrabber.threadPrio" );
395 config( m_fgCpuset,
"framegrabber.cpuset" );
396 if( m_shmimName ==
"" )
397 m_shmimName = derived().configName();
398 config( m_shmimName,
"framegrabber.shmimName" );
400 config( m_circBuffLength,
"framegrabber.circBuffLength" );
402 if( m_circBuffLength < 1 )
404 m_circBuffLength = 1;
405 derivedT::template log<text_log>(
"circBuffLength set to 1" );
408 config( m_latencyCircBuffMaxTime,
"framegrabber.latencyTime" );
409 if( m_latencyCircBuffMaxTime < 0 )
411 m_latencyCircBuffMaxTime = 0;
412 derivedT::template log<text_log>(
"latencyTime set to 0 (off)" );
415 config( m_latencyCircBuffMaxLength,
"framegrabber.latencySize" );
417 if( derivedT::c_frameGrabber_flippable )
419 std::string flip =
"flipNone";
420 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>(
440 { std::string(
"invalid framegrabber flip specification (" ) + flip +
"), setting flipNone" },
441 logPrio::LOG_ERROR );
442 m_defaultFlip = fgFlipNone;
453 m_indiP_shmimName = pcf::IndiProperty( pcf::IndiProperty::Text );
454 m_indiP_shmimName.setDevice( derived().configName() );
455 m_indiP_shmimName.setName(
"fg_shmimName" );
456 m_indiP_shmimName.setPerm( pcf::IndiProperty::ReadOnly );
457 m_indiP_shmimName.setState( pcf::IndiProperty::Idle );
458 m_indiP_shmimName.add( pcf::IndiElement(
"name" ) );
459 m_indiP_shmimName[
"name"] = m_shmimName;
461 if( derived().registerIndiPropertyNew( m_indiP_shmimName,
nullptr ) < 0 )
463#ifndef FRAMEGRABBER_TEST_NOLOG
464 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
470 m_indiP_frameSize = pcf::IndiProperty( pcf::IndiProperty::Number );
471 m_indiP_frameSize.setDevice( derived().configName() );
472 m_indiP_frameSize.setName(
"fg_frameSize" );
473 m_indiP_frameSize.setPerm( pcf::IndiProperty::ReadOnly );
474 m_indiP_frameSize.setState( pcf::IndiProperty::Idle );
475 m_indiP_frameSize.add( pcf::IndiElement(
"width" ) );
476 m_indiP_frameSize[
"width"] = 0;
477 m_indiP_frameSize.add( pcf::IndiElement(
"height" ) );
478 m_indiP_frameSize[
"height"] = 0;
480 if( derived().registerIndiPropertyNew( m_indiP_frameSize,
nullptr ) < 0 )
482#ifndef FRAMEGRABBER_TEST_NOLOG
483 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
489 derived().createROIndiNumber( m_indiP_timing,
"fg_timing" );
490 m_indiP_timing.add( pcf::IndiElement(
"acq_fps" ) );
491 m_indiP_timing.add( pcf::IndiElement(
"acq_min" ) );
492 m_indiP_timing.add( pcf::IndiElement(
"acq_max" ) );
493 m_indiP_timing.add( pcf::IndiElement(
"acq_jitter" ) );
494 m_indiP_timing.add( pcf::IndiElement(
"write_fps" ) );
495 m_indiP_timing.add( pcf::IndiElement(
"write_min" ) );
496 m_indiP_timing.add( pcf::IndiElement(
"write_max" ) );
497 m_indiP_timing.add( pcf::IndiElement(
"write_jitter" ) );
498 m_indiP_timing.add( pcf::IndiElement(
"delta_aw" ) );
499 m_indiP_timing.add( pcf::IndiElement(
"delta_aw_jitter" ) );
501 if( derived().registerIndiPropertyReadOnly( m_indiP_timing ) < 0 )
503#ifndef STDCAMERA_TEST_NOLOG
504 derivedT::template log<software_error>( { __FILE__, __LINE__ } );
510 if( derived().threadStart( m_fgThread,
518 fgThreadStart ) < 0 )
520 derivedT::template log<software_error, -1>( { __FILE__, __LINE__ } );
531 if( pthread_tryjoin_np( m_fgThread.native_handle(), 0 ) == 0 )
533 derivedT::template log<software_error>( { __FILE__, __LINE__,
"framegrabber thread has exited" } );
542 if( m_atimes.size() >= m_atimes.maxEntries() )
545 cbIndexT latTime = m_latencyCircBuffMaxTime * m_cbFPS;
546 if( latTime >= m_atimes.maxEntries() )
548 latTime = m_atimes.maxEntries() - 1;
551 m_atimesD.resize( latTime - 1 );
552 m_wtimesD.resize( latTime - 1 );
553 m_watimesD.resize( latTime - 1 );
555 cbIndexT refEntry = m_atimes.latest();
557 if( refEntry >= latTime )
563 refEntry = m_atimes.maxEntries() + refEntry - latTime;
566 timespec ts = m_atimes.at( refEntry, 0 );
567 double a0 = ts.tv_sec + ( (double)ts.tv_nsec ) / 1e9;
569 ts = m_wtimes.at( refEntry, 0 );
570 double w0 = ts.tv_sec + ( (double)ts.tv_nsec ) / 1e9;
577 for(
size_t n = 1; n <= m_atimesD.size(); ++n )
579 ts = m_atimes.at( refEntry, n );
580 double a = ts.tv_sec + ( (double)ts.tv_nsec ) / 1e9;
582 ts = m_wtimes.at( refEntry, n );
583 double w = ts.tv_sec + ( (double)ts.tv_nsec ) / 1e9;
585 m_atimesD[n - 1] = a - a0;
586 m_wtimesD[n - 1] = w - w0;
587 m_watimesD[n - 1] = w - a;
591 if( m_atimesD[n - 1] < mina )
593 mina = m_atimesD[n - 1];
596 if( m_atimesD[n - 1] > maxa )
598 maxa = m_atimesD[n - 1];
601 if( m_wtimesD[n - 1] < minw )
603 minw = m_wtimesD[n - 1];
606 if( m_wtimesD[n - 1] > maxw )
608 maxw = m_wtimesD[n - 1];
611 if( m_wtimesD[n - 1] < 0 )
613 std::cerr <<
"negative wtime: " << m_wtimesD[n - 1] <<
' ' << n <<
' ' << m_atimesD.size()
614 <<
' ' << refEntry <<
' ' << m_atimes.maxEntries() <<
' ' << latTime <<
'\n';
615 return derivedT::template log<software_error, 0>(
616 { __FILE__, __LINE__,
"negative write time. latency circ buff is not long enought" } );
620 m_mna = mx::math::vectorMean( m_atimesD );
621 m_vara = mx::math::vectorVariance( m_atimesD, m_mna );
625 m_mnw = mx::math::vectorMean( m_wtimesD );
626 m_varw = mx::math::vectorVariance( m_wtimesD, m_mnw );
630 m_mnwa = mx::math::vectorMean( m_watimesD );
631 m_varwa = mx::math::vectorVariance( m_watimesD, m_mnwa );
663 catch(
const std::exception &e )
665 std::cerr << e.what() <<
'\n';
760 m_fgThreadID = syscall( SYS_gettid );
765 while( m_fgThreadInit ==
true && derived().shutdown() == 0 )
770 uint32_t imsize[3] = { 0, 0, 0 };
771 std::string shmimName;
773 while( derived().shutdown() == 0 )
776 while( !derived().shutdown() &&
778 derived().powerState() <= 0 ) )
783 if( derived().shutdown() )
789 if( derived().configureAcquisition() < 0 )
794 m_typeSize = ImageStreamIO_typesize( m_dataType );
797 m_currentFlip = m_defaultFlip;
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_currentFlip )
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 );