339 config(m_fgThreadPrio,
"framegrabber.threadPrio");
340 config(m_fgCpuset,
"framegrabber.cpuset");
341 if(m_shmimName ==
"") m_shmimName = derived().configName();
342 config(m_shmimName,
"framegrabber.shmimName");
344 config(m_circBuffLength,
"framegrabber.circBuffLength");
346 if(m_circBuffLength < 1)
348 m_circBuffLength = 1;
349 derivedT::template log<text_log>(
"circBuffLength set to 1");
352 config(m_latencyCircBuffMaxTime,
"framegrabber.latencyTime");
353 if(m_latencyCircBuffMaxTime < 0)
355 m_latencyCircBuffMaxTime = 0;
356 derivedT::template log<text_log>(
"latencyTime set to 0 (off)");
359 config(m_latencyCircBuffMaxLength,
"framegrabber.latencySize");
362 if(derivedT::c_frameGrabber_flippable)
364 std::string flip =
"flipNone";
365 config(flip,
"framegrabber.defaultFlip");
366 if(flip ==
"flipNone")
368 m_defaultFlip = fgFlipNone;
370 else if(flip ==
"flipUD")
372 m_defaultFlip = fgFlipUD;
374 else if(flip ==
"flipLR")
376 m_defaultFlip = fgFlipLR;
378 else if(flip ==
"flipUDLR")
380 m_defaultFlip = fgFlipUDLR;
384 derivedT::template log<text_log>({std::string(
"invalid framegrabber flip specification (") + flip +
"), setting flipNone"}, logPrio::LOG_ERROR);
385 m_defaultFlip = fgFlipNone;
397 m_indiP_shmimName = pcf::IndiProperty(pcf::IndiProperty::Text);
398 m_indiP_shmimName.setDevice(derived().configName());
399 m_indiP_shmimName.setName(
"fg_shmimName");
400 m_indiP_shmimName.setPerm(pcf::IndiProperty::ReadOnly);
401 m_indiP_shmimName.setState(pcf::IndiProperty::Idle);
402 m_indiP_shmimName.add(pcf::IndiElement(
"name"));
403 m_indiP_shmimName[
"name"] = m_shmimName;
405 if( derived().registerIndiPropertyNew( m_indiP_shmimName,
nullptr) < 0)
407 #ifndef FRAMEGRABBER_TEST_NOLOG
408 derivedT::template log<software_error>({__FILE__,__LINE__});
414 m_indiP_frameSize = pcf::IndiProperty(pcf::IndiProperty::Number);
415 m_indiP_frameSize.setDevice(derived().configName());
416 m_indiP_frameSize.setName(
"fg_frameSize");
417 m_indiP_frameSize.setPerm(pcf::IndiProperty::ReadOnly);
418 m_indiP_frameSize.setState(pcf::IndiProperty::Idle);
419 m_indiP_frameSize.add(pcf::IndiElement(
"width"));
420 m_indiP_frameSize[
"width"] = 0;
421 m_indiP_frameSize.add(pcf::IndiElement(
"height"));
422 m_indiP_frameSize[
"height"] = 0;
424 if( derived().registerIndiPropertyNew( m_indiP_frameSize,
nullptr) < 0)
426 #ifndef FRAMEGRABBER_TEST_NOLOG
427 derivedT::template log<software_error>({__FILE__,__LINE__});
433 derived().createROIndiNumber( m_indiP_timing,
"fg_timing");
434 m_indiP_timing.add(pcf::IndiElement(
"acq_fps"));
435 m_indiP_timing.add(pcf::IndiElement(
"acq_jitter"));
436 m_indiP_timing.add(pcf::IndiElement(
"write_fps"));
437 m_indiP_timing.add(pcf::IndiElement(
"write_jitter"));
438 m_indiP_timing.add(pcf::IndiElement(
"delta_aw"));
439 m_indiP_timing.add(pcf::IndiElement(
"delta_aw_jitter"));
441 if( derived().registerIndiPropertyReadOnly( m_indiP_timing ) < 0)
443 #ifndef STDCAMERA_TEST_NOLOG
444 derivedT::template log<software_error>({__FILE__,__LINE__});
450 if(derived().threadStart( m_fgThread, m_fgThreadInit, m_fgThreadID, m_fgThreadProp, m_fgThreadPrio, m_fgCpuset,
"framegrabber",
this, fgThreadStart) < 0)
452 derivedT::template log<software_error, -1>({__FILE__, __LINE__});
464 if(pthread_tryjoin_np(m_fgThread.native_handle(),0) == 0)
466 derivedT::template log<software_error>({__FILE__, __LINE__,
"framegrabber thread has exited"});
473 if(m_atimes.size() >= m_atimes.maxEntries())
475 cbIndexT refEntry = m_atimes.earliest();
477 m_atimesD.resize(m_atimes.maxEntries()-1);
478 m_wtimesD.resize(m_wtimes.maxEntries()-1);
479 m_watimesD.resize(m_wtimes.maxEntries()-1);
481 double a0 = m_atimes.at(refEntry, 0).tv_sec + ((double) m_atimes.at(refEntry, 0).tv_nsec)/1e9;
482 double w0 = m_wtimes.at(refEntry, 0).tv_sec + ((double) m_wtimes.at(refEntry, 0).tv_nsec)/1e9;
483 for(
size_t n=1; n <= m_atimesD.size(); ++n)
485 double a = m_atimes.at(refEntry, n).tv_sec + ((double) m_atimes.at(refEntry, n).tv_nsec)/1e9;
486 double w = m_wtimes.at(refEntry, n).tv_sec + ((double) m_wtimes.at(refEntry, n).tv_nsec)/1e9;
487 m_atimesD[n-1] = a - a0;
488 m_wtimesD[n-1] = w - w0;
489 m_watimesD[n-1] = w - a;
494 m_mna = mx::math::vectorMean(m_atimesD);
495 m_vara = mx::math::vectorVariance(m_atimesD, m_mna);
497 m_mnw = mx::math::vectorMean(m_wtimesD);
498 m_varw = mx::math::vectorVariance(m_wtimesD, m_mnw);
500 m_mnwa = mx::math::vectorMean(m_watimesD);
501 m_varwa = mx::math::vectorVariance(m_watimesD, m_mnwa);
583 m_fgThreadID = syscall(SYS_gettid);
588 while(m_fgThreadInit ==
true && derived().shutdown() == 0)
593 uint32_t imsize[3] = {0,0,0};
594 std::string shmimName;
596 while(derived().shutdown() == 0)
604 if(derived().shutdown())
continue;
608 if(derived().configureAcquisition() < 0)
continue;
610 if(m_latencyCircBuffMaxLength == 0 || m_latencyCircBuffMaxTime == 0)
612 m_atimes.maxEntries(0);
613 m_wtimes.maxEntries(0);
618 cbIndexT cbSz = m_latencyCircBuffMaxTime * derived().fps();
619 if(cbSz > m_latencyCircBuffMaxLength) cbSz = m_latencyCircBuffMaxLength;
620 if(cbSz < 3) cbSz = 3;
621 m_atimes.maxEntries(cbSz);
622 m_wtimes.maxEntries(cbSz);
625 m_typeSize = ImageStreamIO_typesize(m_dataType);
629 m_currentFlip = m_defaultFlip;
634 if(m_shmimName ==
"") m_shmimName = derived().configName();
636 if(m_width != imsize[0] || m_height != imsize[1] || m_circBuffLength != imsize[2] || m_shmimName != shmimName || m_imageStream ==
nullptr)
638 if(m_imageStream !=
nullptr)
640 ImageStreamIO_destroyIm(m_imageStream);
644 m_imageStream = (IMAGE *) malloc(
sizeof(IMAGE));
647 imsize[1] = m_height;
648 imsize[2] = m_circBuffLength;
649 shmimName = m_shmimName;
651 std::cerr <<
"Creating: " << m_shmimName <<
" " << m_width <<
" " << m_height <<
" " << m_circBuffLength <<
"\n";
653 ImageStreamIO_createIm_gpu(m_imageStream, m_shmimName.c_str(), 3, imsize, m_dataType, -1, 1, IMAGE_NB_SEMAPHORE, 0, CIRCULAR_BUFFER | ZAXIS_TEMPORAL, 0);
655 m_imageStream->md->cnt1 = m_circBuffLength - 1;
659 std::cerr <<
"Not creating . . .\n";
665 if(derived().startAcquisition() < 0)
continue;
667 uint64_t next_cnt1 = 0;
668 char * next_dest = (
char *) m_imageStream->array.raw;
669 timespec * next_wtimearr = &m_imageStream->writetimearray[0];
670 timespec * next_atimearr = &m_imageStream->atimearray[0];
671 uint64_t * next_cntarr = &m_imageStream->cntarray[0];
674 while(!derived().shutdown() && !m_reconfig && derived().powerState() > 0)
679 int isValid = derived().acquireAndCheckValid();
686 else if( isValid > 0)
693 m_imageStream->md->write=1;
696 clock_gettime(CLOCK_REALTIME, &writestart);
698 if(derived().loadImageIntoStream(next_dest) < 0)
704 clock_gettime(CLOCK_REALTIME, &m_imageStream->md->writetime);
707 m_imageStream->md->atime = m_currImageTimestamp;
710 m_imageStream->md->cnt1 = next_cnt1;
713 m_imageStream->md->cnt0++;
715 *next_wtimearr = m_imageStream->md->writetime;
716 *next_atimearr = m_currImageTimestamp;
717 *next_cntarr = m_imageStream->md->cnt0;
720 m_imageStream->md->write=0;
721 ImageStreamIO_sempost(m_imageStream,-1);
724 if(m_atimes.maxEntries() > 0)
726 m_atimes.nextEntry(m_imageStream->md->atime);
727 m_wtimes.nextEntry(m_imageStream->md->writetime);
731 next_cnt1 = m_imageStream->md->cnt1+1;
732 if(next_cnt1 >= m_circBuffLength) next_cnt1 = 0;
734 next_dest = (
char *) m_imageStream->array.raw + next_cnt1*m_width*m_height*m_typeSize;
735 next_wtimearr = &m_imageStream->writetimearray[next_cnt1];
736 next_atimearr = &m_imageStream->atimearray[next_cnt1];
737 next_cntarr = &m_imageStream->cntarray[next_cnt1];
740 m_dummy_c = next_dest[0];
741 m_dummy_ts.tv_sec = next_wtimearr[0].tv_sec + next_atimearr[0].tv_sec;
742 m_dummy_cnt = next_cntarr[0];
745 if(m_reconfig && !derived().shutdown())
747 derived().reconfig();
752 if(m_imageStream !=
nullptr)
754 ImageStreamIO_destroyIm( m_imageStream );
756 m_imageStream =
nullptr;
768 if(!derivedT::c_frameGrabber_flippable)
770 return memcpy(dest, src, width*height*szof);
774 switch(m_currentFlip)
777 return mx::improc::imcpy(dest, src, width, height, szof);
779 return mx::improc::imcpy_flipUD(dest, src, width, height, szof);
781 return mx::improc::imcpy_flipLR(dest, src, width, height, szof);
783 return mx::improc::imcpy_flipUDLR(dest, src, width, height, szof);
795 if( !derived().m_indiDriver )
return 0;
803 if(m_mna != 0 ) fpsa = 1.0/m_mna;
804 if(m_mnw != 0 ) fpsw = 1.0/m_mnw;
806 indi::updateIfChanged<double>(m_indiP_timing, {
"acq_fps",
"acq_jitter",
"write_fps",
"write_jitter",
"delta_aw",
"delta_aw_jitter"},
807 {fpsa, sqrt(m_vara), fpsw, sqrt(m_varw), m_mnwa, sqrt(m_varwa)},derived().m_indiDriver);