/* Receiver */ void CUtilizeFACData::ProcessDataInternal(CParameter& ReceiverParam) { /* Do not use received FAC data in case of simulation */ { bCRCOk = FACReceive.FACParam(pvecInputData, ReceiverParam); if (bCRCOk == TRUE) { PostWinMessage(MS_FAC_CRC, 0); } else { PostWinMessage(MS_FAC_CRC, 2); } } if (bCRCOk == FALSE) { /* If FAC CRC check failed we should increase the frame-counter manually. If only FAC data was corrupted, the others can still decode if they have the right frame number. In case of simulation no FAC data is used, we have to increase the counter here */ ReceiverParam.iFrameIDReceiv++; if (ReceiverParam.iFrameIDReceiv == NUM_FRAMES_IN_SUPERFRAME) ReceiverParam.iFrameIDReceiv = 0; } }
void CSoundBase::run() { // Set thread priority (The working thread should have a higher // priority than the GUI) #ifdef _WIN32 SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); #else /* // set the process to realtime privs, taken from // "http://www.gardena.net/benno/linux/audio" but does not seem to work, // maybe a problem with user rights struct sched_param schp; memset ( &schp, 0, sizeof ( schp ) ); schp.sched_priority = sched_get_priority_max ( SCHED_FIFO ); sched_setscheduler ( 0, SCHED_FIFO, &schp ); */ #endif // main loop of working thread while ( bRun ) { // get audio from sound card (blocking function) if ( Read ( vecsAudioSndCrdStereo ) ) { PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_RED ); } else { PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_GREEN ); } // process audio data (*fpProcessCallback) ( vecsAudioSndCrdStereo, pProcessCallbackArg ); // play the new block if ( Write ( vecsAudioSndCrdStereo ) ) { PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_RED ); } else { PostWinMessage ( MS_SOUND_OUT, MUL_COL_LED_GREEN ); } } }
/* Implementation *************************************************************/ void CSyncUsingPil::ProcessDataInternal(CParameter& ReceiverParam) { int i; /**************************************************************************\ * Frame synchronization detection * \**************************************************************************/ _BOOLEAN bSymbolIDHasChanged = FALSE; if ((bSyncInput == FALSE) && (bAquisition == TRUE)) { #ifdef USE_DRM_FRAME_SYNC_IR_BASED /* DRM frame synchronization using impulse response ----------------- */ /* We assume that the current received OFDM symbol is the first symbol in a DRM frame and estimate the channel transfer function at the pilot positions (the positions of pilots in the first OFDM symbol in a DRM frame). Then we calculate an FFT to get the impulse response of the channel. If the assumption was correct and this really was the correct OFDM symbol, we will get something which looks like an impulse response (contains peaks -> peak-to-average ratio is high). If not, we will certainly get only noise -> no peaks -> peak to average ratio is small. This is because the transmitted values at the pilot positions are different from the values at the pilot cells when transmitting the correct OFDM symbol (which we assumed) */ /* Pick pilot positions and calculate "test" channel estimation */ int iCurIndex = 0; for (i = 0; i < iNumCarrier; i++) { if (_IsScatPil(ReceiverParam.matiMapTab[0][i])) { /* Get channel estimate */ veccChan[iCurIndex] = (*pvecInputData)[i] / ReceiverParam.matcPilotCells[0][i]; /* We have to introduce a new index because not on all carriers is a pilot */ iCurIndex++; } } /* Calculate abs(IFFT) for getting estimate of impulse response */ vecrTestImpResp = Abs(Ifft(veccChan, FftPlan)); /* Calculate peak to average */ const CReal rResultIREst = Max(vecrTestImpResp) / Sum(vecrTestImpResp); /* Store correlation results in a shift register for finding the peak */ vecrCorrHistory.AddEnd(rResultIREst); #else /* DRM frame synchronization based on time pilots ------------------- */ /* Calculate correlation of received cells with pilot pairs */ CReal rResultPilPairCorr = (CReal) 0.0; for (i = 0; i < iNumPilPairs; i++) { /* Actual correlation */ const CComplex cCorrRes = (*pvecInputData)[vecPilCorr[i].iIdx1] * Conj(vecPilCorr[i].cPil1) * Conj((*pvecInputData)[vecPilCorr[i].iIdx2]) * vecPilCorr[i].cPil2 * cR_HH; rResultPilPairCorr += Real(cCorrRes); } /* Store correlation results in a shift register for finding the peak */ vecrCorrHistory.AddEnd(rResultPilPairCorr); #endif /* Finding beginning of DRM frame in results ------------------------ */ /* Wait until history is filled completly */ if (iInitCntFraSy > 0) iInitCntFraSy--; else { /* Search for maximum */ int iMaxIndex = 0; CReal rMaxValue = -_MAXREAL; for (i = 0; i < iNumSymPerFrame; i++) { if (vecrCorrHistory[i] > rMaxValue) { rMaxValue = vecrCorrHistory[i]; iMaxIndex = i; } } /* For initial frame synchronization, use maximum directly */ if (bInitFrameSync == TRUE) { /* Reset init flag */ bInitFrameSync = FALSE; /* Set symbol ID index according to received data */ iSymbCntFraSy = iNumSymPerFrame - iMaxIndex - 1; } else { /* If maximum is in the middle of the interval (check frame sync) */ if (iMaxIndex == iMiddleOfInterval) { if (iSymbCntFraSy == iNumSymPerFrame - iMiddleOfInterval - 1) { /* Reset flags */ bBadFrameSync = FALSE; bFrameSyncWasOK = TRUE; /* Post Message for GUI (Good frame sync) */ PostWinMessage(MS_FRAME_SYNC, 0); /* green */ } else { if (bBadFrameSync == TRUE) { /* Reset symbol ID index according to received data */ iSymbCntFraSy = iNumSymPerFrame - iMiddleOfInterval - 1; /* Inform that symbol ID has changed */ bSymbolIDHasChanged = TRUE; /* Reset flag */ bBadFrameSync = FALSE; PostWinMessage(MS_FRAME_SYNC, 2); /* red */ } else { /* One false detected frame sync should not reset the actual frame sync because the measurement could be wrong. Sometimes the frame sync detection gets false results. If the next time the frame sync is still unequal to the measurement, then correct it */ bBadFrameSync = TRUE; if (bFrameSyncWasOK == TRUE) { /* Post Message that frame sync was wrong but was not yet corrected (yellow light) */ PostWinMessage(MS_FRAME_SYNC, 1); /* yellow */ } else PostWinMessage(MS_FRAME_SYNC, 2); /* red */ } /* Set flag for bad sync */ bFrameSyncWasOK = FALSE; } } } } } else { /* Frame synchronization has successfully finished, show always green light */ PostWinMessage(MS_FRAME_SYNC, 0); } /* Set current symbol ID and flag in extended data of output vector */ (*pvecOutputData).GetExData().iSymbolID = iSymbCntFraSy; (*pvecOutputData).GetExData().bSymbolIDHasChanged = bSymbolIDHasChanged; /* Increase symbol counter and take care of wrap around */ iSymbCntFraSy++; if (iSymbCntFraSy >= iNumSymPerFrame) iSymbCntFraSy = 0; /**************************************************************************\ * Using Frequency pilot information * \**************************************************************************/ if ((bSyncInput == FALSE) && (bTrackPil == TRUE)) { CComplex cFreqOffEstVecSym = CComplex((CReal) 0.0, (CReal) 0.0); for (i = 0; i < NUM_FREQ_PILOTS; i++) { /* The old pilots must be rotated due to timing corrections */ const CComplex cOldFreqPilCorr = Rotate(cOldFreqPil[i], iPosFreqPil[i], (*pvecInputData).GetExData().iCurTimeCorr); /* Calculate the inner product of the sum */ const CComplex cCurPilMult = (*pvecInputData)[iPosFreqPil[i]] * Conj(cOldFreqPilCorr); /* Save "old" frequency pilots for next symbol. Special treatment for robustness mode D (carriers 7 and 21) necessary (See 8.4.2.2) */ if ((ReceiverParam.GetWaveMode() == RM_ROBUSTNESS_MODE_E) && (i < 2)) { cOldFreqPil[i] = -(*pvecInputData)[iPosFreqPil[i]]; } else cOldFreqPil[i] = (*pvecInputData)[iPosFreqPil[i]]; #ifdef USE_SAMOFFS_TRACK_FRE_PIL /* Get phase difference for sample rate offset estimation. Average the vector, real and imaginary part separately */ IIR1(cFreqPilotPhDiff[i], cCurPilMult, rLamSamRaOff); #endif /* Calculate estimation of frequency offset */ cFreqOffEstVecSym += cCurPilMult; } /* Frequency offset ------------------------------------------------- */ /* Correct frequency offset estimation for resample offset corrections. When a sample rate offset correction was applied, the frequency offset is shifted proportional to this correction. The correction is mandatory if large sample rate offsets occur */ /* Get sample rate offset change */ const CReal rDiffSamOffset = rPrevSamRateOffset - ReceiverParam.rResampleOffset; /* Save current resample offset for next symbol */ rPrevSamRateOffset = ReceiverParam.rResampleOffset; /* Correct sample-rate offset correction according to the proportional rule. Use relative DC frequency offset plus relative average offset of frequency pilots to the DC frequency. Normalize this offset so that it can be used as a phase correction for frequency offset estimation */ CReal rPhaseCorr = (ReceiverParam.rFreqOffsetAcqui + ReceiverParam.rFreqOffsetTrack + rAvFreqPilDistToDC) * rDiffSamOffset / SOUNDCRD_SAMPLE_RATE / rNormConstFOE; /* Actual correction (rotate vector) */ cFreqOffVec *= CComplex(Cos(rPhaseCorr), Sin(rPhaseCorr)); /* Average vector, real and imaginary part separately */ IIR1(cFreqOffVec, cFreqOffEstVecSym, rLamFreqOff); /* Calculate argument */ const CReal rFreqOffsetEst = Angle(cFreqOffVec); /* Correct measurement average for actually applied frequency correction */ cFreqOffVec *= CComplex(Cos(-rFreqOffsetEst), Sin(-rFreqOffsetEst)); #ifndef USE_FRQOFFS_TRACK_GUARDCORR /* Integrate the result for controling the frequency offset, normalize estimate */ ReceiverParam.rFreqOffsetTrack += rFreqOffsetEst * rNormConstFOE; #endif #ifdef USE_SAMOFFS_TRACK_FRE_PIL /* Sample rate offset ----------------------------------------------- */ /* Calculate estimation of sample frequency offset. We use the different frequency offset estimations of the frequency pilots. We normalize them with the distance between them and average the result (/ 2.0) */ CReal rSampFreqOffsetEst = ((Angle(cFreqPilotPhDiff[1]) - Angle(cFreqPilotPhDiff[0])) / (iPosFreqPil[1] - iPosFreqPil[0]) + (Angle(cFreqPilotPhDiff[2]) - Angle(cFreqPilotPhDiff[0])) / (iPosFreqPil[2] - iPosFreqPil[0])) / (CReal) 2.0; /* Integrate the result for controling the resampling */ ReceiverParam.rResampleOffset += CONTR_SAMP_OFF_INTEGRATION * rSampFreqOffsetEst; #endif #ifdef _DEBUG_ /* Save frequency and sample rate tracking */ static FILE* pFile = fopen("test/freqtrack.dat", "w"); fprintf(pFile, "%e %e\n", SOUNDCRD_SAMPLE_RATE * ReceiverParam.rFreqOffsetTrack, ReceiverParam.rResampleOffset); fflush(pFile); #endif } /* If synchronized DRM input stream is used, overwrite the detected frequency offest estimate by "0", because we know this value */ if (bSyncInput == TRUE) ReceiverParam.rFreqOffsetTrack = (CReal) 0.0; /* Do not ship data before first frame synchronization was done. The flag "bAquisition" must not be set to FALSE since in that case we would run into an infinite loop since we would not ever ship any data. But since the flag is set after this module, we should be fine with that. */ if ((bInitFrameSync == TRUE) && (bSyncInput == FALSE)) iOutputBlockSize = 0; else { iOutputBlockSize = iNumCarrier; /* Copy data from input to the output. Data is not modified in this module */ for (i = 0; i < iOutputBlockSize; i++) (*pvecOutputData)[i] = (*pvecInputData)[i]; } }
/******************************************************************************\ * Decoder * \******************************************************************************/ void CDataDecoder::ProcessDataInternal(CParameter& ReceiverParam) { int i, j; int iPacketID; int iNewContInd; int iNewPacketDataSize; int iOldPacketDataSize; int iNumSkipBytes; _BINARY biFirstFlag; _BINARY biLastFlag; _BINARY biPadPackInd; CCRC CRCObject; /* Check if something went wrong in the initialization routine */ if (DoNotProcessData == TRUE) return; /* CRC check for all packets -------------------------------------------- */ /* Reset bit extraction access */ (*pvecInputData).ResetBitAccess(); for (j = 0; j < iNumDataPackets; j++) { /* Check the CRC of this packet */ CRCObject.Reset(16); /* "- 2": 16 bits for CRC at the end */ for (i = 0; i < iTotalPacketSize - 2; i++) CRCObject.AddByte((_BYTE) (*pvecInputData).Separate(SIZEOF__BYTE)); /* Store result in vector and show CRC in multimedia window */ if (CRCObject.CheckCRC((*pvecInputData).Separate(16)) == TRUE) { veciCRCOk[j] = 1; /* CRC ok */ PostWinMessage(MS_MSC_CRC, 0); /* Green light */ } else { veciCRCOk[j] = 0; /* CRC wrong */ PostWinMessage(MS_MSC_CRC, 2); /* Red light */ } } /* Extract packet data -------------------------------------------------- */ /* Reset bit extraction access */ (*pvecInputData).ResetBitAccess(); for (j = 0; j < iNumDataPackets; j++) { /* Check if CRC was ok */ if (veciCRCOk[j] == 1) { /* Read header data --------------------------------------------- */ /* First flag */ biFirstFlag = (_BINARY) (*pvecInputData).Separate(1); /* Last flag */ biLastFlag = (_BINARY) (*pvecInputData).Separate(1); /* Packet ID */ iPacketID = (int) (*pvecInputData).Separate(2); /* Padded packet indicator (PPI) */ biPadPackInd = (_BINARY) (*pvecInputData).Separate(1); /* Continuity index (CI) */ iNewContInd = (int) (*pvecInputData).Separate(3); /* Act on parameters given in header */ /* Continuity index: this 3-bit field shall increment by one modulo-8 for each packet with this packet Id */ if ((iContInd[iPacketID] + 1) % 8 != iNewContInd) DataUnit[iPacketID].bOK = FALSE; /* Store continuity index */ iContInd[iPacketID] = iNewContInd; /* Reset flag for data unit ok when receiving the first packet of a new data unit */ if (biFirstFlag == TRUE) { DataUnit[iPacketID].Reset(); DataUnit[iPacketID].bOK = TRUE; } /* If all packets are received correctely, data unit is ready */ if (biLastFlag == TRUE) if (DataUnit[iPacketID].bOK == TRUE) DataUnit[iPacketID].bReady = TRUE; /* Data field --------------------------------------------------- */ /* Get size of new data block */ if (biPadPackInd == TRUE) { /* Padding is present: the first byte gives the number of useful data bytes in the data field. */ iNewPacketDataSize = (int) (*pvecInputData).Separate(SIZEOF__BYTE) * SIZEOF__BYTE; if (iNewPacketDataSize > iMaxPacketDataSize) { /* Error, reset flags */ DataUnit[iPacketID].bOK = FALSE; DataUnit[iPacketID].bReady = FALSE; /* Set values to read complete packet size */ iNewPacketDataSize = iNewPacketDataSize; iNumSkipBytes = 2; /* Only CRC has to be skipped */ } else { /* Number of unused bytes ("- 2" because we also have the one byte which stored the size, the other byte is the header) */ iNumSkipBytes = iTotalPacketSize - 2 - iNewPacketDataSize / SIZEOF__BYTE; } /* Packets with no useful data are permitted if no packet data is available to fill the logical frame. The PPI shall be set to 1 and the first byte of the data field shall be set to 0 to indicate no useful data. The first and last flags shall be set to 1. The continuity index shall be incremented for these empty packets */ if ((biFirstFlag == TRUE) && (biLastFlag == TRUE) && (iNewPacketDataSize == 0)) { /* Packet with no useful data, reset flag */ DataUnit[iPacketID].bReady = FALSE; } } else { iNewPacketDataSize = iMaxPacketDataSize; /* All bytes are useful bytes, only CRC has to be skipped */ iNumSkipBytes = 2; } /* Add new data to data unit vector (bit-wise copying) */ iOldPacketDataSize = DataUnit[iPacketID].vecbiData.Size(); DataUnit[iPacketID].vecbiData.Enlarge(iNewPacketDataSize); /* Read useful bits */ for (i = 0; i < iNewPacketDataSize; i++) DataUnit[iPacketID].vecbiData[iOldPacketDataSize + i] = (_BINARY) (*pvecInputData).Separate(1); /* Read bytes which are not used */ for (i = 0; i < iNumSkipBytes; i++) (*pvecInputData).Separate(SIZEOF__BYTE); /* Use data unit ------------------------------------------------ */ if (DataUnit[iPacketID].bReady == TRUE) { /* Decode all IDs regardless whether activated or not (iPacketID == or != iServPacketID) */ /* Only DAB multimedia is supported */ switch (eAppType) { case AT_MOTSLISHOW: /* MOTSlideshow */ /* Packet unit decoding */ MOTSlideShow[iPacketID]. AddDataUnit(DataUnit[iPacketID].vecbiData); break; case AT_JOURNALINE: break; } /* Packet was used, reset it now for new filling with new data (this will also reset the flag "DataUnit[iPacketID].bReady") */ DataUnit[iPacketID].Reset(); } } else { /* Skip incorrect packet */ for (i = 0; i < iTotalPacketSize; i++) (*pvecInputData).Separate(SIZEOF__BYTE); } } }