From ce1e8e28ce047d9f77f8e82b5755949a454607e7 Mon Sep 17 00:00:00 2001 From: Niklas Eiling Date: Mon, 9 Jan 2023 14:12:32 +0100 Subject: [PATCH] move formatting of printing to stdout to separate class and make in configurable Signed-off-by: Niklas Eiling --- fpga/include/villas/fpga/utils.hpp | 81 ++++++++++++++++++++++++++++++ fpga/src/villas-fpga-ctrl.cpp | 29 ++++------- 2 files changed, 92 insertions(+), 18 deletions(-) diff --git a/fpga/include/villas/fpga/utils.hpp b/fpga/include/villas/fpga/utils.hpp index fae15afde..ecbcacc2b 100644 --- a/fpga/include/villas/fpga/utils.hpp +++ b/fpga/include/villas/fpga/utils.hpp @@ -62,6 +62,87 @@ protected: bool dmaLoopback; }; +class BufferedSampleFormatter { +public: + virtual void format(float value) = 0; + virtual void output(std::ostream& out) + { + out << buf.data() << std::flush; + clearBuf(); + } + virtual void clearBuf() + { + for (size_t i = 0; i < bufSamples && buf[i*bufSampleSize] != '\0'; i++) { + buf[i*bufSampleSize] = '\0'; + } + currentBufLoc = 0; + } +protected: + std::vector buf; + const size_t bufSamples; + const size_t bufSampleSize; + size_t currentBufLoc; + + BufferedSampleFormatter(const size_t bufSamples, const size_t bufSampleSize) : + buf(bufSamples*bufSampleSize+1), // Leave room for a final `\0' + bufSamples(bufSamples), + bufSampleSize(bufSampleSize), + currentBufLoc(0) {}; + BufferedSampleFormatter() = delete; + BufferedSampleFormatter(const BufferedSampleFormatter&) = delete; + virtual char* nextBufPos() + { + return &buf[(currentBufLoc++)*bufSampleSize]; + } +}; + +class BufferedSampleFormatterShort : public BufferedSampleFormatter { +public: + BufferedSampleFormatterShort(size_t bufSizeInSamples) : + BufferedSampleFormatter(bufSizeInSamples, formatStringSize) {}; + + virtual void format(float value) override + { + if (std::snprintf(nextBufPos(), formatStringSize+1, formatString, value) > (int)formatStringSize) { + throw RuntimeError("Output buffer too small"); + } + } + +protected: + static constexpr char formatString[] = "%7f\n"; + static constexpr size_t formatStringSize = 9; +}; + +class BufferedSampleFormatterLong : public BufferedSampleFormatter { +public: + BufferedSampleFormatterLong(size_t bufSizeInSamples) : + BufferedSampleFormatter(bufSizeInSamples, formatStringSize), + sampleCnt(0) {}; + + virtual void format(float value) override + { + if (std::snprintf(nextBufPos(), formatStringSize+1, formatString, sampleCnt, value) > (int)formatStringSize) { + throw RuntimeError("Output buffer too small"); + } + sampleCnt = (sampleCnt+1)%100000; + } + +protected: + static constexpr char formatString[] = "%05zd: %7f\n"; + static constexpr size_t formatStringSize = 16; + size_t sampleCnt; +}; + +std::unique_ptr getBufferedSampleFormatter(const std::string &format, size_t bufSizeInSamples) +{ + if (format == "long") { + return std::make_unique(bufSizeInSamples); + } else if (format == "short") { + return std::make_unique(bufSizeInSamples); + } else { + throw RuntimeError("Unknown output format '{}'", format); + } +} } /* namespace fpga */ } /* namespace villas */ diff --git a/fpga/src/villas-fpga-ctrl.cpp b/fpga/src/villas-fpga-ctrl.cpp index b6de02200..2d73f7c4f 100644 --- a/fpga/src/villas-fpga-ctrl.cpp +++ b/fpga/src/villas-fpga-ctrl.cpp @@ -36,7 +36,8 @@ static std::shared_ptr pciDevices; static auto logger = villas::logging.get("ctrl"); -void readFromDmaToStdOut(std::shared_ptr dma) +void readFromDmaToStdOut(std::shared_ptr dma, + std::unique_ptr formatter) { auto &alloc = villas::HostRam::getAllocator(); @@ -56,33 +57,24 @@ void readFromDmaToStdOut(std::shared_ptr dma) size_t cur = 0, next = 1; std::ios::sync_with_stdio(false); - size_t samplecnt = 0; - static const char outputfmt[] = "%05zd: %7f\n"; - static const size_t outputfmtSize = 16; - char outputbuf[16][outputfmtSize] = {0}; size_t bytesRead; // Setup read transfer dma->read(*block[0], block[0]->getSize()); while (true) { - //logger->debug("Read from stream and write to address {:p}", *block[next]); + logger->trace("Read from stream and write to address {}:{:p}", block[next]->getAddrSpaceId(), block[next]->getOffset()); + // We could use the number of interrupts to determine if we missed a chunk of data dma->read(*block[next], block[next]->getSize()); bytesRead = dma->readComplete(); for (size_t i = 0; i*4 < bytesRead; i++) { int32_t ival = mem[cur][i]; float fval = *((float*)(&ival)); // cppcheck-suppress invalidPointerCast - //std::cerr << std::hex << ival << ","; - //std::cout << samplecnt++ << ": " << fval << '\n'; - if (std::snprintf(outputbuf[i], outputfmtSize+1, outputfmt, (samplecnt++%100000), fval) > (int)outputfmtSize) { - throw RuntimeError("Output buffer too small"); - } + formatter->format(fval); } - for (size_t i = 0; i < sizeof(outputbuf)/sizeof(outputbuf[0])-bytesRead/4; i++) { - outputbuf[i][0] = '\0'; - } - std::cout << *outputbuf << std::flush; + formatter->output(std::cout); + cur = next; next = (next + 1) % (sizeof(mem) / sizeof(mem[0])); } @@ -104,6 +96,8 @@ int main(int argc, char* argv[]) app.add_option("-x,--connect", connectStr, "Connect a FPGA port with another or stdin/stdout"); bool noDma = false; app.add_flag("--no-dma", noDma, "Do not setup DMA, only setup FPGA and Crossbar links"); + std::string outputFormat = "short"; + app.add_option("--output-format", outputFormat, "Output format (short, long)"); app.parse(argc, argv); @@ -117,8 +111,6 @@ int main(int argc, char* argv[]) return 1; } - - auto card = fpga::setupFpgaCard(configFile, fpgaName); std::vector> aurora_channels; @@ -149,7 +141,8 @@ int main(int argc, char* argv[]) parsedConnectString.configCrossBar(dma, aurora_channels); if (!noDma) { - readFromDmaToStdOut(std::move(dma)); + auto formatter = fpga::getBufferedSampleFormatter(outputFormat, 16); + readFromDmaToStdOut(std::move(dma), std::move(formatter)); } } catch (const RuntimeError &e) { logger->error("Error: {}", e.what());