void InitSoraTx(BlinkParams *params) { writeSoraCtx *ctx = (writeSoraCtx *)inmem_malloc(sizeof(writeSoraCtx)); params->TXBuffer = (PVOID)ctx; ctx->prepareBuf = 0; ctx->transferBuf = 0; ctx->firstTx = 0; ctx->lastTx = 0; ctx->idleTXDetected = 0; ctx->TXBufferSize = params->radioParams.TXBufferSize; printf("TX-sora-tx-buffer-size=%ld, cmd-fifo-queue-size=%d, no-tx-bufs=%d\n", ctx->TXBufferSize, cmd_fifo_queue_size, no_tx_bufs); for (int i = 0; i < no_tx_bufs; i++) { ctx->TXBuffers[i] = SoraUAllocBuffer(ctx->TXBufferSize * sizeof(complex16)); // alloc tx sample buffers if (ctx->TXBuffers[i] == NULL) { fprintf(stderr, "Error: Fail to allocate Sora Tx buffer memory!\n"); exit(1); } // Set to 0 as it is not expensive in init and can be useful for gaps between packets memset(ctx->TXBuffers[i], 0, params->radioParams.TXBufferSize * sizeof(complex16)); } }
void InitSoraRx(BlinkParams *params) { HRESULT hr; ULONG nRxBufSize = 0; readSoraCtx *rctx = (readSoraCtx *)inmem_malloc(sizeof(readSoraCtx)); params->TXBuffer = (PVOID)rctx; // Create queue between worker and RX // (only used if READ_IN_WORKER_THREAD defined) size_t size = 28*sizeof(complex16); rctx->readQueue = s_ts_init(1, &size); // Map Rx Buffer hr = SoraURadioMapRxSampleBuf( params->radioParams.radioId, ¶ms->pRxBuf, & nRxBufSize); if ( FAILED (hr) ) { fprintf (stderr, "Error: Fail to map Sora Rx buffer!\n" ); exit(1); } // Generate a sample stream from mapped Rx buffer params->radioParams.dev = (SoraRadioParam *)inmem_malloc(sizeof(SoraRadioParam)); SoraURadioAllocRxStream(&(params->radioParams.dev->RxStream), params->radioParams.radioId, (PUCHAR)params->pRxBuf, nRxBufSize); }
void InitSoraRx(BlinkParams *params) { HRESULT hr; ULONG nRxBufSize = 0; // Map Rx Buffer hr = SoraURadioMapRxSampleBuf( params->radioParams.radioId, ¶ms->pRxBuf, & nRxBufSize); if ( FAILED (hr) ) { fprintf (stderr, "Error: Fail to map Sora Rx buffer!\n" ); exit(1); } // Generate a sample stream from mapped Rx buffer params->radioParams.dev = (SoraRadioParam *)inmem_malloc(sizeof(SoraRadioParam)); SoraURadioAllocRxStream(&(params->radioParams.dev->RxStream), params->radioParams.radioId, (PUCHAR)params->pRxBuf, nRxBufSize); }
// Transit a buffer of <size> complex16 numbers void writeSora(BlinkParams *params, complex16 *ptr, ULONG size) { HRESULT hr; static int indexSrc = 0; int indexPtr = 0; writeSoraCtx *ctx = (writeSoraCtx *)params->TXBuffer; complex16 *remainBuf = ptr; ULONG remainCnt = size; int nextPrepareBuf; static complex16 *syncBuf1 = NULL, *syncBuf2 = NULL; static bool sendSendSyncPreamb = true; static LONG TXCnt = 0; #ifdef DEBUG_LOSSES static complex16 incArr[2000]; static int incAddInd = 0; #endif #ifndef DEBUG_TXRX // Init sync buffer if (syncBuf1 == NULL) { syncBuf1 = (complex16*)inmem_malloc(ctx->TXBufferSize * sizeof(complex16)); syncBuf2 = (complex16*)inmem_malloc(ctx->TXBufferSize * sizeof(complex16)); if (syncBuf1 == NULL || syncBuf2 == NULL) { printf("Cannot malloc syncBufs!\n"); exit(1); } for (int i = 0; i < ctx->TXBufferSize; i++) { syncBuf1[i].re = i; syncBuf1[i].im = i; syncBuf2[i].re = 0; syncBuf2[i].im = 0; } } #endif // Wait until both TX and RX are done with init before starting sync if (!tx_init_done) { printf("TX C Init done...\n"); fflush(stdout); #ifdef DEBUG_LOSSES // Create test sequence for (int i = 0; i < 2000; i++) { incArr[i].re = (i % 1000); incArr[i].im = (i % 1000); } #endif } tx_init_done = true; while (!rx_init_done); #ifdef DEBUG_LOSSES // Send test sequence instead of the real one ptr = incArr + incAddInd; incAddInd = (incAddInd + size) % 1000; #endif #ifndef DEBUG_TXRX // 2s delay before syncing const int syncPreambLen = ((2*30720000) / (int) ctx->TXBufferSize); // Send special sequence // Sequence starts with bunch of 0s to wait until the firmware's queues stabilize // and then sends a ramp that is detected by the RX. Data transmission continues // immediately after the ramp so after it we are in sync with RX. if (sendSendSyncPreamb) { nextPrepareBuf = (ctx->prepareBuf + 1) % no_tx_bufs; for (int syncBufCnt = 0; syncBufCnt <= syncPreambLen; syncBufCnt++) { complex16 *currentBuf = (complex16*)ctx->TXBuffers[ctx->prepareBuf]; if (syncBufCnt == syncPreambLen) { memcpy((void *)currentBuf, (void *)syncBuf1, ctx->TXBufferSize * sizeof(complex16)); } else { memcpy((void *)currentBuf, (void *)syncBuf2, ctx->TXBufferSize * sizeof(complex16)); } // Spin wait until there is a space in the buffer queue while (nextPrepareBuf == ctx->transferBuf) { ctx->prepareBlocked++; } // Full buffer ready to be sent // We don't really send here. // We just advance the pointer and release the record // to be transferred and sent by other threads ctx->prepareBuf = nextPrepareBuf; nextPrepareBuf = (ctx->prepareBuf + 1) % no_tx_bufs; indexSrc = 0; } sendSendSyncPreamb = false; } #ifndef DEBUG_LOSSES // Set the bit on LSB RXTX Sync channel // For speed we set the bit only once every RXTX_SYNC_PERIOD (10ms - 1 frame) // and we don't reset the bit otherwise. We count on this bit being random so // we'll detect out of sync in on average 20ms if (TXCnt == 0) { ptr[0].re |= 1; ptr[0].im |= 1; } else if (TXCnt + size > RXTX_SYNC_PERIOD) { ptr[RXTX_SYNC_PERIOD - TXCnt - 1].re |= 1; ptr[RXTX_SYNC_PERIOD - TXCnt - 1].im |= 1; } TXCnt = (TXCnt + size) % RXTX_SYNC_PERIOD; #endif #endif nextPrepareBuf = (ctx->prepareBuf + 1) % no_tx_bufs; while (remainCnt > 0) { ULONG inc = min(ctx->TXBufferSize - indexSrc, remainCnt); complex16 *currentBuf = (complex16*)ctx->TXBuffers[ctx->prepareBuf]; memcpy((void *)(currentBuf + indexSrc), (void *)(ptr + indexPtr), inc * sizeof(complex16)); indexPtr += inc; indexSrc += inc; remainCnt -= inc; if (indexSrc >= ctx->TXBufferSize) { bool block = false; // Spin wait until there is a space in the buffer queue while (nextPrepareBuf == ctx->transferBuf) { block = true; } if (block) ctx->prepareBlocked++; // Full buffer ready to be sent // We don't really send here. // We just advance the pointer and release the record // to be transferred and sent by other threads ctx->prepareBuf = nextPrepareBuf; nextPrepareBuf = (ctx->prepareBuf + 1) % no_tx_bufs; indexSrc = 0; } } }