// 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); }
void Dot11ATxApp(const Config& config) { SampleBufferSize = _M(2); SampleBuffer = SoraUAllocBuffer(SampleBufferSize); printf("tx buffer: %08x\n", SampleBuffer); printf("tx buffer size: %08x\n", SampleBufferSize); if (SampleBuffer == NULL) return; PreparePacket(config, (PVOID)SampleBuffer, (ULONG)SampleBufferSize); HRESULT hr; do { //Generate Signal hr = BB11ATxFrameMod(&TxVector, &Packet); printf("GenSignal return %08x\n", hr); printf("Signal bytes = %d\n", Packet.Reserved3); /*{ PCOMPLEX8 pSampleBuffer = (PCOMPLEX8)SampleBuffer; for (i = 0; i < Packet.Reserved3; i++) printf("(%5d, %5d)\t", pSampleBuffer[i].re, pSampleBuffer[i].im); printf("\n"); }*/ hr = SoraURadioTransferEx(TARGET_RADIO, SampleBuffer, Packet.Reserved3, &TxID); printf("transfer, hr=%08x, id=%d\n", hr, TxID); FAILED_BREAK(hr); Monitor monitor; TxContext ctx(config, monitor); HANDLE hTxThread = AllocStartThread(DoDot11ATx, &ctx); if (SUCCEEDED(hr) && hTxThread) { printf("\n\nPress any key to exit the program\n"); time_t start = time(NULL); while(!_kbhit()) { if (config.Interval() != 0 && difftime(time(NULL), start) >= config.Interval()) break; } StopFreeThread(hTxThread); hr = SoraURadioTxFree(TARGET_RADIO, TxID); printf("tx free return %08x\n", hr); } } while (FALSE); SoraUReleaseBuffer((PVOID)SampleBuffer); printf("unmap tx buffer ret: %08x\n", hr); printf("Tx out.\n"); }
HRESULT UmxSender::Deinit() { if (!initialized) return -1; HRESULT hr = -1; HRESULT ret = S_OK; if (transferAllocated) { hr = SoraURadioTxFree(Radio::Current()->GetRadioNum(), txID); logger->Log(LOG_FUNC_CALL, L"SoraURadioTxFree called for radio %d\r\n", Radio::Current()->GetRadioNum()); if (FAILED(hr)) { logger->Log(LOG_ERROR, L"Failed. ret = %x\r\n", hr); ret = -1; } else { logger->Log(LOG_SUCCESS, L"success\r\n"); txID = -1; } transferAllocated = false; } if (sampleBuf) { hr = SoraURadioUnmapTxSampleBuf(Radio::Current()->GetRadioNum(), (PVOID)sampleBuf); logger->Log(LOG_FUNC_CALL, L"SoraURadioUnmapTxSampleBuf called for radio %d\r\n", Radio::Current()->GetRadioNum()); if (FAILED(hr)) { logger->Log(LOG_ERROR, L"Failed. ret = %x\r\n", hr); ret = -1; } else { logger->Log(LOG_SUCCESS, L"success\r\n"); sampleBuf = 0; } } initialized = false; return ret; }
void Dot11BTxApp(const Config& config) { HRESULT hr; if (Dot11BTxInit() < 0) return; Dot11BPreparePacket(config, (PVOID)SampleBuffer, (ULONG)SampleBufferSize); do { // Generate Signal hr = BB11BPMDPacketGenSignal(&Packet, &TxVector, (PUCHAR)TempBuffer, TempBufferSize); printf("[dot11b:tx] GenSignal return %08x\n", hr); printf("[dot11b:tx] Signal bytes=%d\n", Packet.Reserved3); hr = SoraURadioTransferEx(TARGET_RADIO, SampleBuffer, Packet.Reserved3, &TxID); printf("[dot11b:tx] transfer, hr=%08x, id=%d\n", hr, TxID); FAILED_BREAK(hr); Monitor monitor; TxContext ctx(config, monitor); HANDLE hTxThread = AllocStartThread(DoDot11BTx, &ctx); if (SUCCEEDED(hr)) { printf("\n\nPress any key to exit the program\n"); time_t start = time(NULL); while(!_kbhit()) { if (config.Interval() != 0 && difftime(time(NULL), start) >= config.Interval()) break; } StopFreeThread(hTxThread); hr = SoraURadioTxFree(TARGET_RADIO, TxID); printf("[dot11b:tx] tx free return %08x\n", hr); } } while(false); Dot11BTxClean(); printf("[dot11b:tx] Tx out.\n"); }
// 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; }