HRESULT UmxSender::Transmit(bool log) { if (!transferAllocated) return -1; HRESULT hr = -1; hr = SoraURadioTx(Radio::Current()->GetRadioNum(), txID); if (log) { logger->Log(LOG_FUNC_CALL, L"SoraURadioTx called for radio %d\n", Radio::Current()->GetRadioNum()); } if (FAILED(hr)) { logger->Log(LOG_ERROR, L"SoraURadioTx failed. ret = %x\r\n", hr); return -1; } else { if (log) { logger->Log(LOG_SUCCESS, L"success\n"); } return S_OK; } }
BOOLEAN DoDot11BTx(void* ctx) { // Alias Monitor& monitor = ((TxContext *)ctx)->monitor; const Config& config = ((TxContext *)ctx)->config; monitor.Query(true); HRESULT hr = SoraURadioTx(TARGET_RADIO, TxID); if (FAILED(hr)) { printf("[dot11b:tx] tx failed\n"); //break; } else { monitor.IncGoodCounter(); monitor.IncThroughput(config.GetPayloadLength()); } // Note: if we send too fast, the RX part cannot demodulate all the frames, // and the performance depends on the entry time, ie. not same in every experiment. SoraStallWait(&tsinfo, 10000); // not to send too fast return TRUE; }
// Transit a buffer of <size> complex16 numbers // ptr has to be 16 aligned and has to have space for x8 complex16 numbers, due to efficien packing to complex8 void writeSora(BlinkParams *params, complex16 *ptr, ULONG size) { HRESULT hr; ULONG TxID; ULONG dbg=0; if (size*2 > params->radioParams.TXBufferSize) { fprintf (stderr, "Error: Sora Tx buffer too small (%ld needed)!\n", 2*size ); exit(1); } // Saturated packing need 16-bit aligned pointers since it uses SSE if ((ULONG)ptr & 0xF > 0) { fprintf (stderr, "Error: Tx ptr has to be 16 aligned!\n"); exit(1); } // Saturated pack from complex16 (default Blink TX type) to complex8 vcs *vPtr = (vcs*)ptr; unsigned int index = 0; for(int i=0; i<size/4; i+=2) { vcs s1, s2; s1 = vPtr[i]; s2 = vPtr[i+1]; vcb b = (vcb)saturated_pack((vs&)s1, (vs&)s2); char *dst = (char *) params->TXBuffer; memcpy((void*)(dst+index), (void*) (&b), sizeof(vcb)); index += sizeof(vcb); } // DEBUG: //hr = SoraURadioTransferEx(params->radioParams.radioId, params->TXBuffer, 2*size, &TxID); hr = SoraURadioTransferEx(params->radioParams.radioId, params->TXBuffer, 4*size, &TxID); if (!SUCCEEDED(hr)) { fprintf (stderr, "Error: Fail to transfer Sora Tx buffer!\n" ); exit(1); } hr = SoraURadioTx(params->radioParams.radioId, TxID); if (!SUCCEEDED(hr)) { fprintf (stderr, "Error: Fail to transmit Sora Tx buffer!\n" ); exit(1); } hr = SoraURadioTxFree(params->radioParams.radioId, TxID); }
BOOLEAN DoDot11ATx(void* ctx) { // Alias Monitor& monitor = ((TxContext *)ctx)->monitor; const Config& config = ((TxContext *)ctx)->config; monitor.Query(true); HRESULT hr = SoraURadioTx(TARGET_RADIO, TxID); if (FAILED(hr)) { printf("[dot11b:tx] tx failed\n"); //break; } else { monitor.IncGoodCounter(); monitor.IncThroughput(config.GetPayloadLength()); } SoraStallWait(&tsinfo, 10000); // not to send too fast return TRUE; }
// Buffers are ready, transfer them DWORD WINAPI SoraTXWorker(void * pParam) { HRESULT hr = S_OK; bool transferred = false; bool idle_detected = FALSE; writeSoraCtx *ctx = (writeSoraCtx *)pParam; ULONG firstTx32, lastTx32; ULONG cnt_tx = 0, cnt_rx = 0; ULONG samp_PC_queue_ptr = 0; ULONG samp_FPGA_queue_ptr = 0; ULONG samp_queue_subsample = 0; memset(samp_PC_queue, 0, sizeof(ULONGLONG)*MAX_NO_TX_BUFS); memset(samp_FPGA_queue, 0, sizeof(ULONGLONG)*MAX_CMD_FIFO_QUEUE_SIZE); samp_RX_queue_full = 0; samp_RX_queue_free = 0; bool blockPC = false; bool blockFPGA = false; ctx->idleTXDetected = 0; ULONGLONG cnt_rnd = 0; cnt_samp_FPGA_underflow = 0; memset(samp_FPGA_underflow, 0, sizeof(ULONGLONG)* DEB_MAX_UNDERFLOW_QUEUE); while (!rx_init_done || !tx_init_done); // Synchronize initial queue positions hr = ReadRegister(0x0550, &lastTx32); hr = ReadRegister(0x0554, &firstTx32); ctx->lastTx = lastTx32; ctx->firstTx = firstTx32; // TODO: here we might want to cache-align all the data to avoid cache misses while (true) { bool bPC = ctx->transferBuf != ctx->prepareBuf; bool bFPGA = diff_wrap(ctx->lastTx, ctx->firstTx) < cmd_fifo_queue_size; blockPC = blockPC || (!bPC); blockFPGA = blockFPGA || (!bFPGA); if (bPC && bFPGA) { int queuePos = ctx->lastTx % cmd_fifo_queue_size; hr = SoraURadioTransferEx(TARGET_RADIO_TX, ctx->TXBuffers[ctx->transferBuf], ctx->TXBufferSize * sizeof(complex16), &(ctx->BufID[queuePos])); hr = SoraURadioTx(TARGET_RADIO_TX, ctx->BufID[queuePos]); ctx->lastTx++; if (!SUCCEEDED(hr)) { printf("SoraURadioTransferEx %d failed!\n", ctx->transferBuf); return FALSE; } ctx->transferBuf = (ctx->transferBuf + 1) % no_tx_bufs; // Store queue size samples for debugging ULONG d1 = diff_wrap_max((ULONG)ctx->prepareBuf, (ULONG)ctx->transferBuf, no_tx_bufs); d1 = min(d1, MAX_NO_TX_BUFS); ULONG d2 = diff_wrap_max(ctx->lastTx, ctx->firstTx, cmd_fifo_queue_size); d2 = min(d2, MAX_CMD_FIFO_QUEUE_SIZE); samp_PC_queue[d1] ++; samp_FPGA_queue[d2] ++; if (d2 < 6) { samp_FPGA_underflow[cnt_samp_FPGA_underflow] = cnt_rnd + 1; cnt_samp_FPGA_underflow = min(cnt_samp_FPGA_underflow + 1, DEB_MAX_UNDERFLOW_QUEUE); } if (blockPC) ctx->transferBlocked++; if (blockFPGA) ctx->transferBlockedFPGA++; blockPC = false; blockFPGA = false; } hr = ReadRegister(0x0550, &lastTx32); hr = ReadRegister(0x0554, &firstTx32); // Don't free the one just dequeued as the transmission could still be ongoing // Only free once the subsequent has been dequeued // Althoug 1 here makes sense, empirically seems that 2 is the minimum while (diff_wrap(firstTx32, ctx->firstTx) > 2) { hr = SoraURadioTxFree(TARGET_RADIO_TX, ctx->BufID[ctx->firstTx % cmd_fifo_queue_size]); ctx->firstTx++; } /* // Indeed, it never happened so removed to speed up the code if (lastTx32 != ctx->lastTx) { printf("This should not happen!\n"); } */ // For some reason we cannot read Sora from this thread, as timing collapses. Didn't spend much time investigating this issue. /* #ifdef READ_IN_WORKER_THREAD readSoraAndQueue(); #endif */ cnt_rnd++; } ctx->TXRunning = false; return 0; }