// $Header: G:/SwDev/WDM/Video/bt848/rcs/Pisces.cpp 1.15 1998/05/04 23:48:53 tomz Exp $ #include "pisces.h" #include /* */ BtPisces::BtPisces( DWORD *xtals ) : Engine_(), Inited_( false ), Even_( CAPTURE_EVEN, VF_Even,&COLOR_EVEN, &WSWAP_EVEN, &BSWAP_EVEN ), Odd_( CAPTURE_ODD, VF_Odd, &COLOR_ODD, &WSWAP_ODD, &BSWAP_ODD ), VBIE_( CAPTURE_VBI_EVEN ), VBIO_( CAPTURE_VBI_ODD ), Update_( false ), nSkipped_( 0 ), Paused_( false ), Starter_( ), SyncEvenEnd1_( ), SyncEvenEnd2_( ), SyncOddEnd1_( ), SyncOddEnd2_( ), PsDecoder_( xtals ), dwPlanarAdjust_( 0 ), CONSTRUCT_COLORCONTROL, CONSTRUCT_INTERRUPTSTATUS, CONSTRUCT_INTERRUPTMASK, CONSTRUCT_CONTROL, CONSTRUCT_CAPTURECONTROL, CONSTRUCT_COLORFORMAT, CONSTRUCT_GPIOOUTPUTENABLECONTROL, CONSTRUCT_GPIODATAIO { Trace t("BtPisces::BtPisces()"); Init(); } BtPisces::~BtPisces() { Trace t("BtPisces::~BtPisces()"); Engine_.Stop(); InterruptMask = 0; InterruptStatus = AllFs; // prevent risc program destructor from gpf-ing SyncEvenEnd1_.SetParent( NULL ); SyncEvenEnd2_.SetParent( NULL ); SyncOddEnd1_.SetParent( NULL ); SyncOddEnd2_.SetParent( NULL ); // free the association array now int ArrSize = sizeof( InterruptToIdx_ ) / sizeof( InterruptToIdx_ [0] ); while ( --ArrSize >= 0 ) delete InterruptToIdx_ [ArrSize]; // now is the Skippers_' turn ArrSize = sizeof( Skippers_ ) / sizeof( Skippers_ [0] ); while ( --ArrSize >= 0 ) delete Skippers_ [ArrSize]; } /* Method: BtPisces::GetIdxFromStream * Purpose: Returns starting index in the program array for a field * Input: aStream: StreamInfo & - reference * Output: int : Index */ int BtPisces::GetIdxFromStream( Field &aStream ) { Trace t("BtPisces::GetIdxFromStream()"); switch ( aStream.GetStreamID() ) { case VS_Field1: return OddStartLocation; case VS_Field2: return EvenStartLocation; case VS_VBI1: return VBIOStartLocation; case VS_VBI2: return VBIEStartLocation; default: return 0; } } /* Method: BtPisces::CreateSyncCodes * Purpose: Creates the risc programs with sync codes needed between data risc * programs * Input: None * Output: ErrorCode */ bool BtPisces::CreateSyncCodes() { Trace t("BtPisces::CreateSyncCodes()"); bool bRet = SyncEvenEnd1_.Create( SC_VRE ) == Success && SyncEvenEnd2_.Create( SC_VRE ) == Success && SyncOddEnd1_.Create( SC_VRO ) == Success && SyncOddEnd2_.Create( SC_VRO ) == Success && Starter_.Create( SC_VRO ) == Success; DebugOut((1, "*** BtPisces::CreateSyncCodes SyncEvenEnd1_(%x)\n", &SyncEvenEnd1_)); DebugOut((1, "*** BtPisces::CreateSyncCodes SyncEvenEnd2_(%x)\n", &SyncEvenEnd2_)); DebugOut((1, "*** BtPisces::CreateSyncCodes SyncOddEnd1_(%x)\n", &SyncOddEnd1_)); DebugOut((1, "*** BtPisces::CreateSyncCodes SyncOddEnd2_(%x)\n", &SyncOddEnd2_)); DebugOut((1, "*** BtPisces::CreateSyncCodes Starter_(%x)\n", &Starter_)); return( bRet ); } /* Method: BtPisces::Init * Purpose: Performs all necessary initialization * Input: None * Output: None */ void BtPisces::Init() { Trace t("BtPisces::Init()"); InterruptStatus = AllFs; InterruptStatus = 0; GAMMA = 1; // initialize the arrays CreatedProgs_.Clear() ; ActiveProgs_.Clear() ; // fill in the skippers array and make each program a 'skipper' DataBuf buf; // [!!!] [TMZ] // Engine_.CreateProgram constants look questionable for ( int i = 0; i < sizeof( Skippers_ ) / sizeof( Skippers_ [0] ); i++ ) { if ( i & 1 ) { MSize s( 10, 10 ); Skippers_ [i] = Engine_.CreateProgram( s, 10 * 2, CF_VBI, buf, true, 0, false ); DebugOut((1, "Creating Skipper[%d] == %x\n", i, Skippers_[i])); Engine_.Skip( Skippers_ [i] ); } else { MSize s( 768, 12 ); // now create skippers for the VBI streams Skippers_ [i] = Engine_.CreateProgram( s, 768 * 2, CF_VBI, buf, true, 0, false ); DebugOut((1, "Creating Skipper[%d] == %x\n", i, Skippers_[i])); } if ( !Skippers_ [i] ) return; } // create associations between Created and Skippers int link = 0; for ( i = 0; i < sizeof( SkipperIdxArr_ ) / sizeof( SkipperIdxArr_ [0] ); i++ ) { SkipperIdxArr_ [i] = link; i += link & 1; // advance past the sync program entry link++; } // fill in constant elements; see the table in the .h file CreatedProgs_ [2] = &SyncOddEnd1_; CreatedProgs_ [8] = &SyncOddEnd2_; CreatedProgs_ [5] = &SyncEvenEnd1_; CreatedProgs_ [11] = &SyncEvenEnd2_; // set corresponding sync bits if ( !CreateSyncCodes() ) return; // initialize association array now int ArrSize = sizeof( InterruptToIdx_ ) / sizeof( InterruptToIdx_ [0] ); while ( --ArrSize >= 0 ) { if ( ( InterruptToIdx_ [ArrSize] = new IntrIdxAss() ) == 0 ) return; } Even_.SetFrameRate( 333667 ); Odd_. SetFrameRate( 333667 ); VBIE_.SetFrameRate( 333667 ); VBIO_.SetFrameRate( 333667 ); Odd_. SetStreamID( VS_Field1 ); Even_.SetStreamID( VS_Field2 ); VBIO_.SetStreamID( VS_VBI1 ); VBIE_.SetStreamID( VS_VBI2 ); // finally, can wipe out the prespiration from the forehead Inited_ = true; } /* Method: BtPisces::AssignIntNumbers * Purpose: Assigns numbers to RISC programs that generate interrupt * Input: None * Output: None */ void BtPisces::AssignIntNumbers() { Trace t("BtPisces::AssignIntNumbers()"); int IntrCnt = 0; int limit = ActiveProgs_.NumElements() ; int idx; // initialize InterruptToIdx_ array for ( idx = 0; idx < limit; idx++ ) { IntrIdxAss item( idx, -1 ); *InterruptToIdx_ [idx] = item; } // assign numbers in front of starting program bool first = true; for ( idx = 0; idx < (int) ActiveProgs_.NumElements() ; idx++ ) { RiscPrgHandle pProg = ActiveProgs_ [idx]; //if not skipped and generates an interrupt assign number if ( pProg && pProg->IsInterrupting() ) { if ( first == true ) { first = false; pProg->ResetStatus(); Skippers_ [SkipperIdxArr_ [idx] ]->ResetStatus(); } else { pProg->SetToCount(); Skippers_ [SkipperIdxArr_ [idx] ]->SetToCount(); } IntrIdxAss item( IntrCnt, idx ); *InterruptToIdx_ [IntrCnt] = item; IntrCnt++; } } } /* Method: BtPisces::LinkThePrograms * Purpose: Creates links between the created programs * Input: None * Output: None */ void BtPisces::LinkThePrograms() { Trace t("BtPisces::LinkThePrograms()"); DebugOut((1, "*** Linking Programs\n")); RiscPrgHandle hParent = ActiveProgs_.First(), hChild = NULL, hVeryFirst = NULL, hLastChild = NULL ; if (hParent) { if ( hParent->IsSkipped() ) { int idx = ActiveProgs_.GetIndex(hParent) ; hParent = Skippers_ [SkipperIdxArr_ [idx] ] ; } while (hParent) { if (!hVeryFirst) hVeryFirst = hParent ; if ( hChild = ActiveProgs_.Next()) { if ( hChild->IsSkipped() ) { int idx = ActiveProgs_.GetIndex(hChild) ; hChild = Skippers_ [SkipperIdxArr_ [idx] ] ; } hLastChild = hChild; Engine_.Chain( hParent, hChild ) ; } hParent = hChild ; } // initial jump Engine_.Chain( &Starter_, hVeryFirst ) ; // now create the loop Engine_.Chain( hLastChild ? hLastChild : hVeryFirst, hVeryFirst ) ; } } /* Method: BtPisces::ProcessSyncPrograms() * Purpose: This function unlinks the helper sync programs * Input: None * Output: None */ void BtPisces::ProcessSyncPrograms() { Trace t("BtPisces::ProcessSyncPrograms()"); for ( int i = 0; i < (int) ActiveProgs_.NumElements(); i += ProgsWithinField ) { if ( !ActiveProgs_ [i] && !ActiveProgs_ [i+1] ) { ActiveProgs_ [i+2] = NULL; } else { ActiveProgs_ [i+2] = CreatedProgs_ [i+2]; } } } /* Method: BtPisces::ProcessPresentPrograms * Purpose: * Input: None * Output: None */ void BtPisces::ProcessPresentPrograms() { Trace t("BtPisces::ProcessPresentPrograms()"); // link in/out helper sync programs ProcessSyncPrograms(); // and now is time to cross link the programs LinkThePrograms(); // and now figure out the numbers programs use for interrupts AssignIntNumbers(); } /* Method: BtPisces::AddProgram * Purpose: Creates new RISC program and inserts it in the chain at a proper place * Input: aStream: StreamInfo & - reference to the stream to add a program for * NumberToAdd: int - number of programs to add * Output: * Note: Basically this internal function performs a loop 2 times * //4. Tries to get another buffer to establish double buffering * //5. If buffer is available it creates another RISC program with it * //6. Then it has to link the program in... */ RiscPrgHandle BtPisces::AddProgram( Field &ToStart, int NumberToAdd ) { Trace t("BtPisces::AddProgram()"); DebugOut((1, "BtPisces::AddProgram()\n")); int StartIdx = GetIdxFromStream( ToStart ); SyncCode Sync; int SyncIdx; bool rsync; if ( StartIdx <= OddStartLocation ) { Sync = SC_VRO; SyncIdx = OddSyncStartLoc; rsync = false; } else { Sync = SC_VRE; SyncIdx = EvenSyncStartLoc; rsync = bool( StartIdx == EvenStartLocation ); } // have to know what is the size of the image to produce MRect r; ToStart.GetDigitalWindow( r ); // RISC engine operates on absolute sizes, not rectangles MSize s = r.Size(); int BufCnt = 0; int Idx = StartIdx; for ( ; BufCnt < NumberToAdd; BufCnt++ ) { // init sync programs with a premise tha no data program exists CreatedProgs_ [SyncIdx]->Create( Sync, true ); // obtain the next buffer from queue ( entry is removed from container ) DataBuf buf = ToStart.GetNextBuffer(); // can create a RISC program now. RiscPrgHandle hProgram = Engine_.CreateProgram( s, ToStart.GetBufPitch(), ToStart.GetColorFormat(), buf, ToStart.Interrupt_, dwPlanarAdjust_, rsync ); // store this program CreatedProgs_ [Idx] = hProgram; DebugOut((1, "Creating RiscProgram[%d] == %x\n", Idx, CreatedProgs_ [Idx])); if ( !hProgram ) { Idx -= DistBetweenProgs; if ( Idx >= 0 ) { // clean up previous program Engine_.DestroyProgram( CreatedProgs_ [Idx] ); CreatedProgs_ [Idx] = NULL; } return NULL; } // make sure we unskip the program when buffer becomes available if ( !buf.pData_ ) { hProgram->SetSkipped(); // do not have enough buffers to support double buffering nSkipped_++; } // assign stream to program; makes it easy during interrupt hProgram->SetTag( &ToStart ); SyncIdx += DistBetweenProgs; Idx += DistBetweenProgs; // skip the location intended for the other program } /* endfor */ return CreatedProgs_ [StartIdx]; } /* Method: BtPisces::Create * Purpose: This functions starts the stream. * Input: aStream: StreamInfo & - reference to a stream to start * Output: Address of the Starter_ * Note: After the Start 2 entries in the CreatedProgs_ are created. Starting * location is 4 for even and 1 for odd. Increment is 6. So if it is the first * invocation and there is enough ( 2 ) buffers present entries [1] and [7] * or [4] and [10] will be filled with newly created RISC programs. When programs * exist for one field only they are doubly linked. When programs exist for * both fields they alternate, i.e. 0->2->1->3->0... When one of the fields * has 1 program only, programs are linked like this: 0->2->1->0->2...(numbers * are indexes in the CreatedProgs_ array ). Alternating programs makes for * maximum frame rate. */ ErrorCode BtPisces::Create( Field &ToCreate ) { Trace t("BtPisces::Create()"); // running full-steam, nothing to create if ( ToCreate.IsStarted() == true ) return Success; int StartIdx = GetIdxFromStream( ToCreate ); if ( CreatedProgs_ [StartIdx] ) return Success; // not running yet, but exists // call into internal function that adds new RISC program if ( ! AddProgram( ToCreate, MaxProgsForField ) ) return Fail; return Success; } /* Method: BtPisces::Start * Purpose: Starts given stream ( by putting in in the Active_ array * Input: ToStart: Field & */ void BtPisces::Start( Field & ToStart ) { Trace t("BtPisces::Start()"); // DebugOut((1, "BtPisces::Start\n")); if ( ToStart.IsStarted() == true ) return; // all we need to do at this point is to create a proper starter // and link the programs in. int idx = GetIdxFromStream( ToStart ); // this loop will enable LinkThePrograms to see programs for this stream for ( int i = 0; i < MaxProgsForField; i++, idx += DistBetweenProgs ) { ActiveProgs_ [idx] = CreatedProgs_ [idx]; } // all I want to do at this point is call Restart. // do not signal the buffers Update_ = false; Restart(); Update_ = true; } /* Method: BtPisces::Stop * Purpose: This function stops a stream. Called when PAUSE SRB is received * Input: aStream: StreamInfo & - reference to a stream to start * Output: None */ void BtPisces::Stop( Field &ToStop ) { Trace t("BtPisces::Stop()"); // DebugOut((1, "BtPisces::Stop\n")); Engine_.Stop(); // no more interrupts int StartIdx = GetIdxFromStream( ToStop ); // prevent unneeded syncronization interrupts IMASK_SCERW = 0; // it is time to pause the stream now ToStop.Stop(); bool Need2Restart = false; // go through the array of programs and killing ones for this field (stream) for ( int i = 0; i < MaxProgsForField; i++, StartIdx += DistBetweenProgs ) { RiscPrgHandle ToDie = CreatedProgs_ [StartIdx]; if ( !ToDie ) // this should never happen continue; if ( ToDie->IsSkipped() ) nSkipped_--; DebugOut((1, "about to destroy idx = %d\n", StartIdx ) ); Engine_.DestroyProgram( ToDie ); CreatedProgs_ [StartIdx] = NULL; ActiveProgs_ [StartIdx] = NULL; // in case Pause wasn't called Need2Restart = true; } /* endfor */ // nobody's around anymore if ( !CreatedProgs_.CountDMAProgs() ) { Engine_.Stop(); InterruptMask = 0; InterruptStatus = AllFs; nSkipped_ = 0; } else { if ( Need2Restart ) { Restart(); // relink the programs and start ones that are alive IMASK_SCERW = 1; // re-enable the sync error interrupts } } } /* Method: BtPisces::Pause * Purpose: This function stops a stream. Called when PAUSE SRB is received * Input: aStream: Field & - reference to a stream to start * Output: None */ void BtPisces::Pause( Field &ToPause ) { Trace t("BtPisces::Pause()"); // DebugOut((1, "BtPisces::Pause\n")); Engine_.Stop(); // no more interrupts if ( !ToPause.IsStarted() ) return; int StartIdx = GetIdxFromStream( ToPause ); // prevent unneeded syncronization interrupts IMASK_SCERW = 0; // it is time to pause the stream now // ToPause.Stop(); - done in Restart // go through the array of programs and killing ones for this field (stream) for ( int i = 0; i < MaxProgsForField; i++, StartIdx += DistBetweenProgs ) { ActiveProgs_ [StartIdx] = NULL; } /* endfor */ Restart(); // relink the programs and start ones that are alive } /* Method: BtPisces::PairedPause * Purpose: This is a hacky function that pauses 2 streams at once * Input: idx: index of the second program in the second field * Output: None */ void BtPisces::PairedPause( int idx ) { Trace t("BtPisces::PairedPause()"); // DebugOut((1, "BtPisces::PairedPause\n")); Engine_.Stop(); // no more interrupts // go through the array of programs and killing ones for this field (stream) for ( int i = 0; i < MaxProgsForField; i++, idx -= DistBetweenProgs ) { ActiveProgs_ [idx] = NULL; ActiveProgs_ [idx-ProgsWithinField] = NULL; } /* endfor */ Restart(); // relink the programs and start ones that are alive } /* Method: BtPisces::GetStarted * Purpose: Figures out the channels that are started * Input: * Output: None */ void BtPisces::GetStarted( bool &EvenWasStarted, bool &OddWasStarted, bool &VBIEWasStarted, bool &VBIOWasStarted ) { Trace t("BtPisces::GetStarted()"); VBIEWasStarted = ( ActiveProgs_ [VBIEStartLocation] ? TRUE : FALSE); EvenWasStarted = ( ActiveProgs_ [EvenStartLocation] ? TRUE : FALSE); VBIOWasStarted = ( ActiveProgs_ [VBIOStartLocation] ? TRUE : FALSE); OddWasStarted = ( ActiveProgs_ [OddStartLocation] ? TRUE : FALSE); } /* Method: BtPisces::RestartStreams * Purpose: Restarts streams that were started * Input: * Output: None */ void BtPisces::RestartStreams( bool EvenWasStarted, bool OddWasStarted, bool VBIEWasStarted, bool VBIOWasStarted ) { Trace t("BtPisces::RestartStream()"); // vbi programs are first to execute, so enable them first if ( VBIOWasStarted ) VBIO_.Start(); if ( OddWasStarted ) Odd_.Start(); if ( VBIEWasStarted ) VBIE_.Start(); if ( EvenWasStarted ) Even_.Start(); } /* Method: BtPisces::CreateStarter * Purpose: Creates proper sync code for the bootstrap program * Input: EvenWasStarted: bool * Output: None */ void BtPisces::CreateStarter( bool EvenWasStarted ) { Trace t("BtPisces::CreateStarter()"); Starter_.Create( EvenWasStarted ? SC_VRE : SC_VRO, true ); DebugOut((1, "*** BtPisces::CreateStarter(%x) buf(%x)\n", &Starter_ , Starter_.GetPhysProgAddr( ))); } /* Method: BtPisces::Restart * Purpose: Restarts the capture process. Called by ISR and Stop() * Input: None * Output: None */ void BtPisces::Restart() { Trace t("BtPisces::Restart()"); bool EvenWasStarted, OddWasStarted, VBIEWasStarted, VBIOWasStarted; GetStarted( EvenWasStarted, OddWasStarted, VBIEWasStarted, VBIOWasStarted ); DebugOut((2, "BtPisces::Restart - Even WasStarted (%d)\n", EvenWasStarted)); DebugOut((2, "BtPisces::Restart - Odd WasStarted (%d)\n", OddWasStarted)); DebugOut((2, "BtPisces::Restart - VBIE WasStarted (%d)\n", VBIEWasStarted)); DebugOut((2, "BtPisces::Restart - VBIO WasStarted (%d)\n", VBIOWasStarted)); Engine_.Stop(); // No more interrupts! Odd_.Stop(); Even_.Stop(); VBIE_.Stop(); VBIO_.Stop(); Engine_.Stop(); // No more interrupts! #if 1 if ( OddWasStarted ) { Odd_.CancelSrbList(); } if ( EvenWasStarted ) { Even_.CancelSrbList(); } if ( VBIEWasStarted ) { VBIE_.CancelSrbList(); } if ( VBIOWasStarted ) { VBIO_.CancelSrbList(); } #endif // this will never happen, probably if ( !EvenWasStarted && !OddWasStarted && !VBIEWasStarted && !VBIOWasStarted ) return; InterruptStatus = AllFs; // clear all the status bits CreateStarter( bool( EvenWasStarted || VBIEWasStarted ) ); ProcessPresentPrograms(); // DumpRiscPrograms(); Engine_.Start( Starter_ ); RestartStreams( EvenWasStarted, OddWasStarted, VBIEWasStarted, VBIOWasStarted ); OldIdx_ = -1; InterruptMask = RISC_I | FBUS_I | OCERR_I | SCERR_I | RIPERR_I | PABORT_I | EN_TRITON1_BUG_FIX; } /* Method: BtPisces::Skip * Purpose: Forces a given program to be skipped by the RISC engine * Input: ToSkip: RiscPrgHandle - program to be skipped * Output: None * Note: If the number of skipped programs equals total number of programs, the * RISC engine is stopped */ void BtPisces::Skip( int idx ) { Trace t("BtPisces::Skip()"); // get the program and skip it RiscPrgHandle ToSkip = ActiveProgs_ [idx]; if ( ToSkip->IsSkipped() ) return; ToSkip->SetSkipped(); nSkipped_++; //skip by linking the Skipper_ in instead of the skippee RiscPrgHandle SkipeeParent = ToSkip->GetParent(); RiscPrgHandle SkipeeChild = ToSkip->GetChild(); // get the skipper for this program RiscPrgHandle pSkipper = Skippers_ [SkipperIdxArr_ [idx] ]; Engine_.Chain( pSkipper, SkipeeChild ); Engine_.Chain( SkipeeParent, pSkipper ); DebugOut((1, "BtPisces::Skipped %d Skipper %d\n", idx, SkipperIdxArr_ [idx] ) ); } inline bool IsFirst( int idx ) { Trace t("BtPisces::IsFirst()"); return bool( idx == OddStartLocation || idx == VBIOStartLocation || idx - DistBetweenProgs == OddStartLocation || idx - DistBetweenProgs == VBIOStartLocation ); } inline bool IsLast( int idx ) { Trace t("BtPisces::IsLast()"); return bool((idx == (VBIEStartLocation + DistBetweenProgs)) || (idx == (EvenStartLocation + DistBetweenProgs))); } /* Method: BtPisces::GetPassed * Purpose: Calculates number of programs that have executed since last interrupt * Input: None * Output: int: number of passed */ int BtPisces::GetPassed() { Trace t("BtPisces::GetPassed()"); // figure out which RISC program caused an interrupt int ProgCnt = RISCS; int numActive = ActiveProgs_.CountDMAProgs() ; if ( ProgCnt >= numActive ) { DebugOut((1, "ProgCnt = %d, larger than created\n", ProgCnt ) ); } // now see how many programs have interrupted since last time and process them all if ( ProgCnt == OldIdx_ ) { DebugOut((1, "ProgCnt is the same = %d\n", ProgCnt ) ); } int passed; if ( ProgCnt < OldIdx_ ) { passed = numActive - OldIdx_ + ProgCnt; // you spin me like a record, baby - round, round... } else passed = ProgCnt - OldIdx_; // The following line of code was VERY bad !!! // This caused crashes when the system got busy and had interrupts backed up. // if ( ProgCnt == OldIdx_ ) // passed = numActive; OldIdx_ = ProgCnt; return passed; } /* Method: BtPisces::GetProgram * Purpose: Finds a RISC program based on its position * Input: None * Output: None */ inline RiscPrgHandle BtPisces::GetProgram( int pos, int &idx ) { Trace t("BtPisces::GetProgram()"); int nActiveProgs = ActiveProgs_.CountDMAProgs( ); if ( nActiveProgs == 0 ) { idx = 0; return ( NULL ); } IntrIdxAss *item; item = InterruptToIdx_ [ pos % nActiveProgs ]; idx = item->Idx; DEBUG_ASSERT( idx != -1 ); return (idx == -1) ? NULL : ActiveProgs_ [idx]; } /* Method: BtPisces::ProcessRISCIntr * Purpose: Handles interrupts caused by the RISC programs * Input: None * Output: None */ void BtPisces::ProcessRISCIntr() { PHW_STREAM_REQUEST_BLOCK gpCurSrb = 0; Trace t("BtPisces::ProcessRISCIntr()"); // this line must be before GetPassed(), as OldIdx_ is changed by that function int pos = OldIdx_ + 1; // measure elapsed time int passed = GetPassed(); DebugOut((1, " passed = %d\n", passed ) ); while ( passed-- > 0 ) { int idx; RiscPrgHandle Rspnsbl = GetProgram( pos, idx ); pos++; // last chance to prevent a disaster... if ( !Rspnsbl || !Rspnsbl->IsInterrupting() ) { DebugOut((1, " no resp or not intr\n" ) ); continue; } // get conveniently saved stream from the program Field &Interrupter = *(Field *)Rspnsbl->GetTag(); gpCurSrb = Rspnsbl->pSrb_; // [TMZ] [!!!] DebugOut((1, "'idx(%d), pSrb(%x)\n", idx, gpCurSrb)); bool paired = Interrupter.GetPaired(); if ( Interrupter.IsStarted() != true ) { DebugOut((1, " not started %d\n", idx ) ); continue; } if ( IsFirst( idx ) && paired ) { DebugOut((1, " continue pair %d\n", idx ) ); continue; } LONGLONG *pL = (LONGLONG *)Rspnsbl->GetDataBuffer(); if ( !pL ) { DebugOut((1, "null buffer in interrupt, ignore this interrupt\n")); //continue; } else { DebugOut((1, "good buffer in interrupt\n")); } // now make sure all buffers are written to if ( !pL || Rspnsbl->IsSkipped() ) { // want to call notify, so ProcessBufferAtInterrupt is called DebugOut((1, " skipped %d\n", idx ) ); Interrupter.Notify( (PVOID)idx, true ); Interrupter.SetReady( true ); } else { BOOL test1 = FALSE; BOOL test2 = FALSE; BOOL test3 = FALSE; if ( 1 //*pL != 0xAAAAAAAA33333333 && (test1 = TRUE) && //*(pL + 1) != 0xBBBBBBBB22222222 && (test2 = TRUE) && //Interrupter.GetReady() && (test3 = TRUE) ) { // here buffer is available DebugOut((1, " notify %d, addr - %x\n", idx, Rspnsbl->GetDataBuffer() ) ); //#pragma message("*** be very carefull zeroing buffers!!!") //Rspnsbl->SetDataBuffer( 0 ); // [TMZ] try to fix buffer re-use bug Interrupter.Notify( (PVOID)idx, false ); Interrupter.SetReady( true ); } else { // add code for the paired streams here DebugOut((1, " not time %d (%d, %d, %d)\n", idx , test1, test2, test3)); // this if/else takes care of this cases: // 1. first buffer for a field is not written to // 2. second buffer for a field is written to ( this can happen when // both programs were updated at the same time, but the timing was // such that first did not start executing, but second was ); // so this if/else prevents sending buffers back out of order if ( Interrupter.GetReady() ) // it is always true before it is ever false Interrupter.SetReady( false ); else // make sure that things are correct when the loop is entered later // the field must be set to 'ready' Interrupter.SetReady( true ); } } } /* endwhile */ } /* Method: BtPiscess::ProcessBufferAtInterrupt * Purpose: Called by a video channel to perform risc program modifications * if needed * Input: pTag: PVOID - pointer to some data ( risc program pointer ) * Output: None */ void BtPisces::ProcessBufferAtInterrupt( PVOID pTag ) { Trace t("BtPisces::ProcessBufferAtInterrupt()"); int idx = (int)pTag; RiscPrgHandle Rspnsbl = ActiveProgs_ [idx]; if ( !Rspnsbl ) { DebugOut((1, "PBAI: no responsible\n")); return; // can this really happen ?? } // get conveniently saved field from the program Field &Interrupter = *(Field *)Rspnsbl->GetTag(); // see if there is a buffer in the queue and get it DataBuf buf = Interrupter.GetNextBuffer(); DebugOut((1, "Update %d %x\n", idx, buf.pData_ ) ); // if buffer is not available skip the program if ( !buf.pData_ ) { DebugOut((1, "Buffer not available, skipping %d\n", idx ) ); Skip( idx ); } else { if ( Rspnsbl->IsSkipped() ) nSkipped_--; Engine_.ChangeAddress( Rspnsbl, buf ); LinkThePrograms(); } } /* Method: BtPisces::Interrupt * Purpose: Called by ISR to initiate the processing of an interrupt * Input: None * Output: None */ State BtPisces::Interrupt() { Trace t("BtPisces::Interrupt()"); DebugOut((2, "BtPisces::Interrupt()\n")); extern BYTE *gpjBaseAddr; DWORD IntrStatus = *(DWORD*)(gpjBaseAddr+0x100); State DidWe = Off; if ( IntrStatus & RISC_I ) { DebugOut((2, "RISC_I\n")); ProcessRISCIntr(); *(DWORD*)(gpjBaseAddr+0x100) = RISC_I; // reset the status bit DidWe = On; } if ( IntrStatus & FBUS_I ) { DebugOut((2, "FBUS\n")); *(DWORD*)(gpjBaseAddr+0x100) = FBUS_I; // reset the status bit DidWe = On; } if ( IntrStatus & FTRGT_I ) { DebugOut((2, "FTRGT\n")); *(DWORD*)(gpjBaseAddr+0x100) = FTRGT_I; // reset the status bit DidWe = On; //[TMZ] } if ( IntrStatus & FDSR_I ) { DebugOut((2, "FDSR\n")); *(DWORD*)(gpjBaseAddr+0x100) = FDSR_I; // reset the status bit DidWe = On; //[TMZ] } if ( IntrStatus & PPERR_I ) { DebugOut((2, "PPERR\n")); *(DWORD*)(gpjBaseAddr+0x100) = PPERR_I; // reset the status bit DidWe = On; //[TMZ] } if ( IntrStatus & RIPERR_I ) { DebugOut((2, "RIPERR\n")); *(DWORD*)(gpjBaseAddr+0x100) = RIPERR_I; // reset the status bit Restart(); DidWe = On; } if ( IntrStatus & PABORT_I ) { DebugOut((2, "PABORT\n")); *(DWORD*)(gpjBaseAddr+0x100) = PABORT_I; // reset the status bit DidWe = On; } if ( IntrStatus & OCERR_I ) { DebugOut((2, "OCERR\n")); DidWe = On; DebugOut((0, "Stopping RiscEngine due to OCERR\n")); // [!!!] [TMZ] why not restart? Engine_.Stop(); *(DWORD*)(gpjBaseAddr+0x100) = OCERR_I; // reset the status bit } if ( IntrStatus & SCERR_I ) { DebugOut((0, "SCERR\n")); DidWe = On; *(DWORD*)(gpjBaseAddr+0x100) = SCERR_I; // reset the status bit Restart(); // [TMZ] [!!!] this royally screws us over sometimes, figure it out. *(DWORD*)(gpjBaseAddr+0x100) = SCERR_I; // reset the status bit } return DidWe; } // resource allocation group /* Method: BtPisces::AllocateStream * Purpose: This function allocates a stream for use by a video channel * Input: StrInf: StreamInfo & - reference to the stream information structure * Output: */ ErrorCode BtPisces::AllocateStream( Field *&ToAllocate, VideoStream st ) { Trace t("BtPisces::AllocateStream()"); switch ( st ) { case VS_Field1: ToAllocate = &Odd_; break; case VS_Field2: ToAllocate = &Even_; break; case VS_VBI1: ToAllocate = &VBIO_; break; case VS_VBI2: ToAllocate = &VBIE_; break; } return Success; } /* Method: BtPisces::SetBrightness * Purpose: Changes brightness of the captured image * Input: * Output: */ void BtPisces::SetBrightness( DWORD value ) { Trace t("BtPisces::SetBrightness()"); PsDecoder_.SetBrightness( value ); } /* Method: BtPisces::SetSaturation * Purpose: * Input: * Output: */ void BtPisces::SetSaturation( DWORD value ) { Trace t("BtPisces::SetSaturation()"); PsDecoder_.SetSaturation( value ); } /* Method: BtPisces::SetConnector * Purpose: * Input: * Output: */ void BtPisces::SetConnector( DWORD value ) { Trace t("BtPisces::SetConnector()"); PsDecoder_.SetVideoInput( Connector( value ) ); } /* Method: BtPisces::SetContrast * Purpose: * Input: * Output: */ void BtPisces::SetContrast( DWORD value ) { Trace t("BtPisces::SetContrast()"); PsDecoder_.SetContrast( value ); } /* Method: BtPisces::SetHue * Purpose: * Input: * Output: */ void BtPisces::SetHue( DWORD value ) { Trace t("BtPisces::SetHue()"); PsDecoder_.SetHue( value ); } /* Method: BtPisces::SetSVideo * Purpose: * Input: * Output: */ void BtPisces::SetSVideo( DWORD ) { Trace t("BtPisces::SetSVideo()"); } /* Method: BtPisces:: * Purpose: * Input: value: DWORD * Output: */ void BtPisces::SetFormat( DWORD value ) { Trace t("BtPisces::SetFormat()"); PsDecoder_.SetVideoFormat( VideoFormat( value ) ); // let the scaler know format has changed Even_.VideoFormatChanged( VideoFormat( value ) ); Odd_.VideoFormatChanged( VideoFormat( value ) ); } /* Method: BtPisces::GetSaturation * Purpose: * Input: pData: PLONG * Output: */ LONG BtPisces::GetSaturation() { Trace t("BtPisces::GetSaturation()"); return PsDecoder_.GetSaturation(); } /* Method: BtPisces::GetHue * Purpose: * Input: pData: PLONG * Output: */ LONG BtPisces::GetHue() { Trace t("BtPisces::GetHue()"); return PsDecoder_.GetHue(); } /* Method: BtPisces::GetBrightness * Purpose: * Input: pData: PLONG * Output: */ LONG BtPisces::GetBrightness() { Trace t("BtPisces::GetBrightness()"); return PsDecoder_.GetBrightness(); } /* Method: BtPisces::GetSVideo * Purpose: * Input: pData: PLONG * Output: */ LONG BtPisces::GetSVideo() { Trace t("BtPisces::GetSVideo()"); return 0; } /* Method: BtPisces::GetContrast * Purpose: * Input: pData: PLONG * Output: */ LONG BtPisces::GetContrast() { Trace t("BtPisces::GetContrast()"); return PsDecoder_.GetContrast(); } /* Method: BtPisces::GetFormat * Purpose: * Input: pData: PLONG * Output: */ LONG BtPisces::GetFormat() { Trace t("BtPisces::GetFormat()"); return PsDecoder_.GetVideoFormat(); } /* Method: BtPisces::GetConnector * Purpose: * Input: pData: PLONG * Output: */ LONG BtPisces::GetConnector() { Trace t("BtPisces::GetConnector()"); return PsDecoder_.GetVideoInput(); } // scaler group /* Method: BtPisces::SetAnalogWindow * Purpose: * Input: * Output: */ ErrorCode BtPisces::SetAnalogWindow( MRect &r, Field &aField ) { Trace t("BtPisces::SetAnalogWindow()"); return aField.SetAnalogWindow( r ); } /* Method: BtPisces::SetDigitalWindow * Purpose: * Input: * Output: */ ErrorCode BtPisces::SetDigitalWindow( MRect &r, Field &aField ) { Trace t("BtPisces::SetDigitalWindow()"); return aField.SetDigitalWindow( r ); } // color space converter group /* Method: BtPisces::SetPixelFormat * Purpose: * Input: * Output: */ void BtPisces::SetPixelFormat( ColFmt aFormat, Field &aField ) { Trace t("BtPisces::SetPixelFormat()"); aField.SetColorFormat( aFormat ); } /* Method: BtPisces::GetPixelFormat * Purpose: * Input: * Output: */ ColFmt BtPisces::GetPixelFormat( Field &aField ) { Trace t("BtPisces::GetPixelFormat()"); return aField.GetColorFormat(); } void BtPisces::TurnVFilter( State s ) { Trace t("BtPisces::TurnVFilter()"); Even_.TurnVFilter( s ); Odd_.TurnVFilter( s ); } /* Method: * Purpose: returns video standards supported by the board */ LONG BtPisces::GetSupportedStandards() { Trace t("BtPisces::GetSupportedStandards()"); return PsDecoder_.GetSupportedStandards(); } void BtPisces::DumpRiscPrograms() { LONG x; // Dump the links DebugOut((0, "------------------------------------------------\n")); for( x = 0; x < 12; x++ ) { if ( CreatedProgs_[x] ) { DebugOut((0, "Created #%02d addr(%x) paddr(%x) jaddr(%x)\n", x, CreatedProgs_[x], CreatedProgs_[x]->GetPhysProgAddr( ), *(CreatedProgs_[x]->pChainAddress_ + 1))); } } for( x = 0; x < 8; x++ ) { if ( Skippers_[x] ) { DebugOut((0, "Skipper #%02d addr(%x) paddr(%x) jaddr(%x)\n", x, Skippers_[x], Skippers_[x]->GetPhysProgAddr( ), *(Skippers_[x]->pChainAddress_ + 1))); } } DebugOut((0, "------------------------------------------------\n")); return ; ///////////////////////////////////////////////// for( x = 0; x < 12; x++ ) { DebugOut((0, "Active Program # %d(%x) buf(%x)\n", x, ActiveProgs_[x], ActiveProgs_[x]?ActiveProgs_[x]->GetPhysProgAddr( ):-1)); } for( x = 0; x < 12; x++ ) { DebugOut((0, "Created Program # %d(%x) buf(%x)\n", x, CreatedProgs_[x], CreatedProgs_[x]?CreatedProgs_[x]->GetPhysProgAddr( ):-1)); } for( x = 0; x < 8; x++ ) { DebugOut((0, "Skipper Program # %d(%x) buf(%x)\n", x, Skippers_[x], Skippers_[x]?Skippers_[x]->GetPhysProgAddr( ):-1)); } DebugOut((2, "---------------------------------\n")); DebugOut((2, "Dumping ActiveProgs_\n")); DebugOut((2, "---------------------------------\n")); for( x = 0; x < 12; x++ ) { DebugOut((1, "Active Program # %d\n", x)); ActiveProgs_[x]->Dump(); } DebugOut((2, "---------------------------------\n")); DebugOut((2, "Dumping CreatedProgs_\n")); DebugOut((2, "---------------------------------\n")); for( x = 0; x < 12; x++ ) { DebugOut((1, "Created Program # %d\n", x)); CreatedProgs_[x]->Dump(); } DebugOut((2, "---------------------------------\n")); DebugOut((2, "Dumping Skippers_\n")); DebugOut((2, "---------------------------------\n")); for( x = 0; x < 8; x++ ) { DebugOut((1, "Skipper Program # %d\n", x)); Skippers_[x]->Dump(); } }