int Seek(int offset) { HRESULT hr; SignalBlock block; if (offset == END_POS) { // Seek to end of the stream, ie. flush all existing blocks in the stream int moved = 0; do { hr = SoraRadioReadRxStream (rxstream_pointer, &rxstream_touched, block); if (FAILED (hr)) break; moved += SignalBlock::size * vcs::size; } while (!rxstream_touched); return moved; } // Note: if the offset is large than available item in the stream currently, // wait until enough, and then seek int expected = offset; while(offset > 0) { hr = SoraRadioReadRxStream (rxstream_pointer, &rxstream_touched, block); if (FAILED (hr)) break; offset -= SignalBlock::size * vcs::size; } return expected - offset; }
bool Process () { int yieldcounter = YIELD_SIGNALBLOCK_COUNT; HRESULT hr; do { // // pump each signal block to downstream // SignalBlock * po = (SignalBlock *) opin().append(); hr = SoraRadioReadRxStream (rxstream_pointer, &rxstream_touched, *po); if ( SUCCEEDED (hr) ) { Next()->Process(opin()); } else { error_code = BK_ERROR_HARDWARE_FAILED; } // Yield to caller to prevent OS hanging // The common cause is the logic error in brick graph, which take long time continuous processing without returning // control to the sora scheduler, so the scheduler doesn't have opportunity to schedule it to other cores. yieldcounter--; if (yieldcounter <= 0) { error_code = BK_ERROR_YIELD; } } while (!rxstream_touched && (error_code == BK_ERROR_SUCCESS)); return true; }
// Calc DC for complex numbers in 4 SignalBlocks, divided by 4 SORA_EXTERN_C HRESULT BB11BGetAccurateDCOffset( IN PSORA_RADIO_RX_STREAM pRxStream, OUT vcs & dcOffset, OUT ULONG * pDescCount, OUT FLAG * touched) { int dcReSum = 0, dcImSum = 0; HRESULT hr = S_OK; ULONG count; SignalBlock block; for (count = 0; count < 4; count++) { hr = SoraRadioReadRxStream(pRxStream, touched, block); FAILED_BREAK(hr); dcOffset = SoraCalcDC(block); dcReSum += dcOffset[0].re; dcImSum += dcOffset[0].im; } *pDescCount += count; dcOffset[0].re = (short)(dcReSum >> 2); dcOffset[0].im = (short)(dcImSum >> 2); set_all(dcOffset, dcOffset[0]); return hr; }
// readSora reads <size> of __int16 inputs from Sora radio // It is a blocking function and returns only once everything is read void readSora(BlinkParams *params, complex16 *ptr, int size) { HRESULT hr; FLAG fReachEnd; // Signal block contains 7 vcs = 28 int16 static SignalBlock block; complex16* pSamples = (complex16*)(&block[0]); static int indexSrc = 28; int oldIndexSrc; complex16* ptrDst = ptr; int remaining = size; if (indexSrc < 28) { oldIndexSrc = indexSrc; // Something has already been read previously, so copy that first memcpy((void *)ptrDst, (void *)(pSamples + indexSrc), min(remaining, 28 - oldIndexSrc)*sizeof(complex16)); indexSrc += min(remaining, 28 - oldIndexSrc); ptrDst += min(remaining, 28 - oldIndexSrc); remaining -= min(remaining, 28 - oldIndexSrc); } while (remaining > 0) { // Read from the radio hr = SoraRadioReadRxStream(&(params->radioParams.dev->RxStream), &fReachEnd, block); if (FAILED(hr)) { fprintf (stderr, "Error: Fail to read Sora Rx buffer!\n" ); exit(1); } indexSrc = 0; // Copy memcpy((void *)ptrDst, (void *)(pSamples + indexSrc), min(remaining, 28)*sizeof(complex16)); indexSrc += min(remaining, 28); ptrDst += min(remaining, 28); remaining -= min(remaining, 28); } }
/*++ BB11BSpd is a simple implementation of software power detection. Return: E_FETCH_SIGNAL_HW_TIMEOUT, E_FETCH_SIGNAL_FORCE_STOPPED, BB11B_E_PD_LAG, BB11B_CHANNEL_CLEAN, BB11B_OK_POWER_DETECTED --*/ HRESULT BB11BSpd(PBB11B_SPD_CONTEXT pSpdContext, PSORA_RADIO_RX_STREAM pRxStream) { // Alias FLAG *b_workIndicator = pSpdContext->b_workIndicator; // pointer to flag, 0 for force stop, 1 for work vcs& DcOffset = (vcs&)pSpdContext->dcOffset; vui& BlockEnergySum = (vui&)pSpdContext->BlockEnergySum; FLAG touched; ULONG PeekBlockCount = 0; HRESULT hr = S_OK; int energyLevel; if (pSpdContext->b_resetFlag) { //DbgPrint("[TEMP1] reset\n"); BB11BSpdResetHistory(pSpdContext); } SignalBlock block; do { if (pSpdContext->b_reestimateOffset) { hr = BB11BGetAccurateDCOffset( pRxStream, DcOffset, &PeekBlockCount, &touched); FAILED_BREAK(hr); pSpdContext->b_reestimateOffset = 0; } while (TRUE) { hr = SoraRadioReadRxStream(pRxStream, &touched, block); FAILED_BREAK(hr); // Check whether force stopped if (*b_workIndicator == 0) { hr = BB11B_E_FORCE_STOP; break; } // Estimate and update DC offset SoraUpdateDC(block, DcOffset); RemoveDC(block, DcOffset); BlockEnergySum = SoraGetNorm(block); PeekBlockCount++; energyLevel = BB11BSpdUpdateEngeryHistoryAndCheckThreshold( pSpdContext, pSpdContext->b_threshold, pSpdContext->b_gainLevel ? pSpdContext->b_thresholdHL : pSpdContext->b_thresholdLH ); if (energyLevel != EL_NOISE) { if (pSpdContext->b_gainLevel == 0 && energyLevel == EL_HIGH) pSpdContext->b_gainLevelNext = 1; else if (pSpdContext->b_gainLevel == 1 && energyLevel == EL_LOW) pSpdContext->b_gainLevelNext = 0; pSpdContext->b_evalEnergy = BlockEnergySum[0]; hr = BB11B_OK_POWER_DETECTED; break; } if (touched && PeekBlockCount > pSpdContext->b_minDescCount) { hr = BB11B_CHANNEL_CLEAN; break; } if (PeekBlockCount >= pSpdContext->b_maxDescCount) { hr = BB11B_E_PD_LAG; break; } } } while(FALSE); pSpdContext->b_dcOffset = DcOffset[0]; return hr; }
// readSora reads <size> of complex16 inputs from Sora radio // It is a blocking function and returns only once everything is read void readSora(BlinkParams *params, complex16 *ptr, int size) { HRESULT hr; FLAG fReachEnd; // Signal block contains 7 vcs = 28 complex16 static SignalBlock block; complex16* pSamples = (complex16*)(&block[0]); static int indexSrc = 28; int oldIndexSrc; complex16* ptrDst = ptr; int remaining = size; readSoraCtx *rctx = (readSoraCtx *)params->TXBuffer; // DEBUG int32 deb_cnt = 0; int16 deb_max = 0; int16 deb_old = 0; // Wait until both TX and RX are done with init before starting sync if (!rx_init_done) { printf("RX C Init done...\n"); fflush(stdout); } rx_init_done = true; while (!tx_init_done); #ifndef DEBUG_TXRX // Wait for the special sync sequence from the TX // before starting to receive data. See TX for description. while (!rctx->RXSynced) { // Read from the radio hr = SoraRadioReadRxStream(&(params->radioParams.dev->RxStream), &fReachEnd, block); if (FAILED(hr)) { // This can happen initially because read is in sync with the write // so some initial reads my timeout. But this will later get in sync // So instead of quitting here we monitor that the number of missed reads goes to 0. //fprintf (stderr, "Error: Fail to read Sora Rx buffer!\n" ); //exit(1); rctx->rxBlocked++; continue; } int i = 0; while (i < 28 && rctx->syncStateCnt < rctx->TXBufferSize - 1) { // DEBUG /* deb_max = max(deb_max, pSamples[i].im); deb_cnt++; if (deb_cnt == 100000000) { printf("DEB: %d\n", deb_max); } if (pSamples[i].im > 0 && (pSamples[i].im - deb_old == 1 || pSamples[i].im > 10000)) printf("%d ", pSamples[i].im); deb_old = pSamples[i].im; */ if (rctx->syncStateCnt + 1 == pSamples[i].im) { rctx->syncStateCnt = pSamples[i].im; } else { static bool printErr = true; if (rctx->syncStateCnt != rctx->TXBufferSize - 28 - 1 && printErr) { printf("rctx->syncStateCnt=%ld, pSamples[%d].im=%d\n", rctx->syncStateCnt, i, pSamples[i].im); printErr = false; } } i++; } if (rctx->syncStateCnt >= rctx->TXBufferSize - 1) { rctx->RXSynced = true; rctx->RXSymbol = 28 - i; rctx->RXFrame = 0; printf("\n**************************************************************************\n"); printf("RX synchronized (syncStateCnt=%ld, i=%d, pSamples[i].im=%d, rxBlocked=%llu, rctx->rxSucc=%llu).\n", rctx->syncStateCnt, i, pSamples[i].im, rctx->rxBlocked, rctx->rxSucc); printf("**************************************************************************\n\n"); #ifndef DEBUG_TXRX_THROUGH // Switch to sending 1-bit sync info SetTXRXSync(1); #endif indexSrc = i; } } #endif if (indexSrc < 28) { oldIndexSrc = indexSrc; // Something has already been read previously, so copy that first memcpy((void *)ptrDst, (void *)(pSamples + indexSrc), min(remaining, 28 - oldIndexSrc)*sizeof(complex16)); indexSrc += min(remaining, 28 - oldIndexSrc); ptrDst += min(remaining, 28 - oldIndexSrc); remaining -= min(remaining, 28 - oldIndexSrc); } while (remaining > 0) { #ifndef READ_IN_WORKER_THREAD // Read from the radio hr = SoraRadioReadRxStream(&(params->radioParams.dev->RxStream), &fReachEnd, block); if (FAILED(hr)) { // This can happen initially because read is in sync with the write // so some initial reads my timeout. But this will later get in sync // So instead of quitting here we monitor that the number of missed reads goes to 0. //fprintf (stderr, "Error: Fail to read Sora Rx buffer!\n" ); //exit(1); rctx->rxBlocked++; continue; } #else readSoraAndQueue(); if (!s_ts_get(rctx->readQueue, 0, (char *)pSamples)) { rctx->rxBlocked++; continue; } #endif rctx->rxSucc++; indexSrc = 0; // Check sync if (rctx->RXSymbol + 28 > RXTX_SYNC_PERIOD) { // DEBUG /* if (rctx->RXFrame % 50 == 0) { printf("%d\n", pSamples[RXTX_SYNC_PERIOD - rctx->RXSymbol].im); } */ if ((pSamples[RXTX_SYNC_PERIOD - rctx->RXSymbol].re & 1) != 1 || (pSamples[RXTX_SYNC_PERIOD - rctx->RXSymbol].im & 1) != 1) { if (outOfSyncs == 0) { printf("First outOfSyncs occured after %llu (%llu, %llu) reads.\n", rctx->rxBlocked + rctx->rxSucc, rctx->rxBlocked, rctx->rxSucc); /* printf("**** Dumping extra stats:\n"); writeSoraCtx *_ctx = (writeSoraCtx *)params_tx->TXBuffer; readSoraCtx *_rctx = (readSoraCtx *)params_rx->TXBuffer; bool outOfSync = printRadioStats(_ctx, _rctx); */ fflush(stdout); } outOfSyncs++; } rctx->RXSymbol = rctx->RXSymbol + 28 - RXTX_SYNC_PERIOD; rctx->RXFrame = (rctx->RXFrame + 1) % 1024; } else { rctx->RXSymbol += 28; } // Copy memcpy((void *)ptrDst, (void *)(pSamples + indexSrc), min(remaining, 28)*sizeof(complex16)); indexSrc += min(remaining, 28); ptrDst += min(remaining, 28); remaining -= min(remaining, 28); } #ifdef DEBUG_LOSSES // In DEBUG_LOSSES mode ignore input since it is copied from TX, can cause false RX, and mess up timing memset(ptr, 0, size*sizeof(complex16)); #endif }