//! Task execution comes here // NOTE: for interlaced cams // for exposures < 2460 ms the cam will aquire an exposure for each frame // i.e. 2.4 sec expo for F1 then send one frame then 2.4 sec for F2 then send the frame // i.e. the receiver thread must have enough time to capture the second one too void Atik16Thread::Entry() { // Sanity check if ( !m_pCaller ) { return; // immediately - this is messy - we cannot even reach our creator } // Thread actions const long WAIT_INTERVALL = 250; // milliseconds // INIT m_exitCode = 0; // task result bool done = false; // task status bool readData = false; // read status bool linger = false; // something left to trash long toRead = 0; // what do we have to read long nRead = 0; // how much is left long readSize = 1; // best read chuncksize long readCount= 0; // counts the already read bytes const long InitNullReads = 20; // allow enough null reads (-> 20 sec) long nullReads = 0; // read=0 counter to allow cam lag times unsigned char* pBuffer = NULL; // will hold the destination ptr ArtTimeHelper bpsTimer; // in read timer long Bps; // Bytes per second value (DL rate) // Sanity check if ( m_dev.DevNULL() ) { m_exitCode = 2; done = true; } // Init FTD m_dev.ftd->SetDefaultBuffer(); m_dev.ftd->SetTimeouts(CAM_RX_TIMEOUT, CAM_TX_TIMEOUT); m_pCaller->ProcessThreadStart(); // and down to the caller /* ----------------------------------------------------------- */ while(!done) { if (m_aborted) { // task was aborted by some m_exitCode = 1; done = true; // thread will die now } else { // process cam states switch (m_pCaller->m_camState) { case CAMERA_IDLE: { ; }// IDLE task break; // nothing to do .. case CAMERA_EXPOSING: { // the cam is now waiting for the exposure to end - next is either READING or FLUSHING m_waitMsRemaining = m_timeHelper.RemainingMSec(); //BM:20090410 - bugfix not showing EXP time if (m_abortExposure) { // waiting ended with abort OnWaitEnd(m_waitMsRemaining); // call with what's left } else if ( m_timeHelper.HasEnded() ) { // waiting ended OnWaitEnd(0); // process below with 0 left }// expo done else { ; // just wait } }// EXPO task break; case CAMERA_READING: { // the cam is reading the CCD - next is DOWNLOADING // not yet in reading state - now reading starts pBuffer = (unsigned char*)m_buffer; // where to write ?? // note: this either reads the camera // or does short exposures i.e. up to ~2.5 secs inplace m_elapsedMs = m_timeHelper.ElapsedMSec(); // real end duration just before CCD is read m_pCaller->ProcessTriggerRDCCD(); // issue the read command down to the camera // reading is done - we prepare DL toRead = m_aquiringLength; // get aquire size nRead = toRead; // set remaining amout linger = false; nullReads = InitNullReads; // number of errors with read == 0 allowed readCount = 0; // read counter (to calc DL percents) readSize = m_dev.ftd->GetAskSize(); // optimal ask size according to manual readData = true; //reading now m_readErrorDetected = false; m_dev.ftd->SetTimeouts(1000, CAM_TX_TIMEOUT); // timeout - 20 retries in the thread m_pCaller->ProcessTriggerDownload(0); // init DL with 0% done and update State bpsTimer.StartNow(); // get the time to calc Bps later // triggers download processing if (m_abortExposure) { m_pCaller->SetCameraState(CAMERA_FLUSHING); // immediate flush } else { m_pCaller->SetCameraState(CAMERA_DOWNLOADING); } }// READING task break; case CAMERA_FLUSHING: { // just readout the cam if needed - next is IDLE again if (readData) { // read remaining bytes from camera // we cannot cancel data collection, once started // so we have to read what's left nullReads = InitNullReads; // number of errors with read == 0 allowed linger = (nRead>0) ? true : false; // something left while (linger && (nullReads>0)) { // do not longer gather data but read the buffers from USB if needed // just read the rest (hogging) size_t read; if ( m_dev.ftd->ReadBYTEsNIL(read) ) { nRead -= read; } else { ::fprintf(stderr, "Atik16Thread - Error reading from camera while flushing !\n"); nullReads = 0; // force error exit m_readErrorDetected = true; } if (read<=0) { nullReads--; // make sure to get to an end once } else { nullReads = InitNullReads; // reset nullreads after getting some } linger = (nRead>0) ? true : false; // something left } nRead = 0; // left to read is forced to 0 now linger = false; // not longer readData = false; // not longer }// was reading OnReadEnd(-1); }// FLUSHING task break; case CAMERA_DOWNLOADING: { // the cam is now downloading the image data - next is IDLE if (nRead>0) { // still something to read size_t read = 0; // get data in chunks that should be optimal if ( m_dev.ftd->ReadBYTEs(pBuffer, (nRead>=readSize)? readSize : nRead, read) ) { // we have read something if (read>0) { // Regular Read: got something readCount += read; nRead -= read; pBuffer+=read; // advance dest ptr if (toRead>0) m_pCaller->ProcessTriggerDownload((readCount *100) / toRead); // update DL status nullReads = InitNullReads; // reset Read Error counter once we got something // continue with next round } else { // Zero Read: read=0 - try more read // again - here we may have to wait for the second 2.46 sec exposure - so be patient... nullReads--; _V_ ::fprintf(stdout, "Atik16Thread - Read 0 bytes: %ld - got %ld waitingfor %ld \n", nullReads, readCount, nRead); if (nullReads<=0) { // too many 0-reads, bail out - cam seems not longer responding (or we expected too much...) ::fprintf(stderr, "Atik16Thread - too many 0 byte reads from camera!\n"); #ifdef _DEBUG ::fprintf(stderr, "Atik16Thread - DEBUG continues!\n"); readData = false; // not longer m_readErrorDetected = false; // we have a read error condition now nRead=0; OnReadEnd(0); // call my creator with success for debug #else readData = false; // not longer m_readErrorDetected = true; // we have a read error condition now nRead=0; OnReadEnd(-1); // call my creator with failure #endif // this will terminate DL } } }// read OK else { // IO Read Error: abort ::fprintf(stderr, "Atik16Thread - Error reading from camera during download!\n"); readData = false; // not longer m_readErrorDetected = true; // we have a read error condition now nRead=0; OnReadEnd(-1); // call my creator with failure // this will terminate DL }// read error }//if something to read else { // regular read end readData = false; // not longer long dlTime = long(bpsTimer.ElapsedMSec()); if (dlTime!=0) Bps = (toRead*1000) / dlTime; //bytes / sec else Bps = 1; m_readErrorDetected = false; OnReadEnd(Bps); // call my creator to indicate read end // this will terminate DL }// DL done }// DOWNLOADING task break; default: { // other state such as CAMERA_ERROR // just waiting ; }//default }//switch if (!readData) m_dev.ftd->Sleep_ms(WAIT_INTERVALL); // now wait a while if not reading }//not aborted }// thread loop OnThreadExit(); // call my creator to expect to shutdown things }
void NTAPI OnTlsCallback(PVOID, DWORD dwReason, PVOID) { if (dwReason == DLL_THREAD_DETACH) OnThreadExit(); }