44 #include <boost/python.hpp>
45namespace bp = boost::python;
81 taps_ =
reinterpret_cast<uint8_t*
>(malloc(
sizeof(uint8_t) * tapCnt_));
87 gettimeofday(&lastRxTime_, NULL);
88 gettimeofday(&lastTxTime_, NULL);
109double ru::Prbs::updateTime(
struct timeval* last) {
118 gettimeofday(&now, NULL);
120 timersub(&now, last, &per);
122 if (timercmp(&per, &cmp, >)) {
123 ret =
static_cast<float>(per.tv_sec) +
static_cast<float>(per.tv_usec) / 1e6;
124 gettimeofday(last, NULL);
132void ru::Prbs::setWidth(uint32_t width) {
133 if ((width > (MaxBytes * 8)) || (width % 32) != 0)
throw(
rogue::GeneralError(
"Prbs::setWidth",
"Invalid width."));
136 std::lock_guard<std::mutex> lockT(pMtx_);
139 byteWidth_ = width / 8;
140 minSize_ = byteWidth_ * 3;
144void ru::Prbs::setTaps(uint32_t tapCnt, uint8_t* taps) {
147 std::lock_guard<std::mutex> lockT(pMtx_);
151 taps_ =
reinterpret_cast<uint8_t*
>(malloc(
sizeof(uint8_t) * tapCnt));
153 for (i = 0; i < tapCnt_; i++) taps_[i] = taps[i];
159void ru::Prbs::setTapsPy(boost::python::object p) {
162 if (PyObject_GetBuffer(p.ptr(), &pyBuf, PyBUF_SIMPLE) < 0)
165 setTaps(pyBuf.len,
reinterpret_cast<uint8_t*
>(pyBuf.buf));
166 PyBuffer_Release(&pyBuf);
172void ru::Prbs::sendCount(
bool state) {
174 std::lock_guard<std::mutex> lockT(pMtx_);
179void ru::Prbs::flfsr(uint8_t* data) {
186 for (x = 0; x < tapCnt_; x++) {
187 iByte = taps_[x] / 8;
189 lsbIn ^= ((data[iByte] >> iBit) & 0x1);
192 for (x = 0; x < byteWidth_; x++) {
193 msbOut = data[x] & 0x80;
201void ru::Prbs::runThread() {
202 txLog_->logThreadId();
206 if ( txPeriod_ > 0 ) usleep(txPeriod_);
211void ru::Prbs::enable(uint32_t size) {
213 if (((size % byteWidth_) != 0) || size < minSize_)
throw rogue::GeneralError(
"Prbs::enable",
"Invalid frame size");
215 if (txThread_ == NULL) {
218 txThread_ =
new std::thread(&Prbs::runThread,
this);
222 pthread_setname_np(txThread_->native_handle(),
"PrbsTx");
228void ru::Prbs::disable() {
229 if (txThread_ != NULL) {
239bool ru::Prbs::getRxEnable() {
244void ru::Prbs::setRxEnable(
bool en) {
252uint32_t ru::Prbs::getRxErrors() {
253 return (rxErrCount_);
257uint32_t ru::Prbs::getRxCount() {
262uint64_t ru::Prbs::getRxBytes() {
267uint32_t ru::Prbs::getTxErrors() {
268 return (txErrCount_);
272uint32_t ru::Prbs::getTxCount() {
277double ru::Prbs::getRxRate() {
282double ru::Prbs::getRxBw() {
287double ru::Prbs::getTxRate() {
292uint32_t ru::Prbs::getTxPeriod() {
297void ru::Prbs::setTxPeriod(uint32_t value) {
302double ru::Prbs::getTxBw() {
307uint64_t ru::Prbs::getTxBytes() {
312void ru::Prbs::checkPayload(
bool state) {
317void ru::Prbs::genPayload(
bool state) {
323void ru::Prbs::resetCount() {
335void ru::Prbs::genFrame(uint32_t size) {
338 uint32_t frSeq[MaxBytes / 4];
339 uint32_t frSize[MaxBytes / 4];
340 uint32_t wCount[MaxBytes / 4];
341 uint8_t data[MaxBytes];
346 std::lock_guard<std::mutex> lock(pMtx_);
349 if (((size % byteWidth_) != 0) || size < minSize_)
353 memset(frSize, 0, MaxBytes);
354 frSize[0] = (size / byteWidth_) - 1;
357 memset(frSeq, 0, MaxBytes);
361 memset(wCount, 0, MaxBytes);
364 fr = reqFrame(size,
true);
365 fr->setPayload(size);
367 frIter = fr->begin();
368 frEnd = frIter + size;
380 std::memcpy(data, frSeq, byteWidth_);
383 while (frIter != frEnd) {
401 if ((per = updateTime(&lastTxTime_)) > 0.0) {
402 txRate_ =
static_cast<double>(txCount_ - lastTxCount_) / per;
403 txBw_ =
static_cast<double>(txBytes_ - lastTxBytes_) / per;
404 lastTxCount_ = txCount_;
405 lastTxBytes_ = txBytes_;
413 uint32_t frSeq[MaxBytes / 4];
414 uint32_t frSize[MaxBytes / 4];
420 uint8_t expData[MaxBytes];
427 while (!rxEnable_) usleep(10000);
430 std::lock_guard<std::mutex> lock(pMtx_);
432 size = frame->getPayload();
433 frIter = frame->begin();
434 frEnd = frame->end();
437 if (frame->getError()) {
438 rxLog_->warning(
"Frame error field is set: 0x%" PRIx8, frame->getError());
444 if (((size % byteWidth_) != 0) || size < minSize_) {
445 rxLog_->warning(
"Size violation size=%" PRIu32
", count=%" PRIu32, size, rxCount_);
453 rxSeq_ = frSeq[0] + 1;
457 expSize = (frSize[0] + 1) * byteWidth_;
462 if ((expSize != size) || (frSeq[0] != 0 && expSeq != 0 && frSeq[0] != expSeq)) {
463 rxLog_->warning(
"Bad header. expSize=%" PRIu32
" gotSize=%" PRIu32
" expSeq=%" PRIu32
" gotSeq=%" PRIu32
464 " nxtSeq=%" PRIu32
" count=%" PRIu32,
478 std::memcpy(expData, frSeq, byteWidth_);
482 while (frIter != frEnd) {
485 if (!std::equal(frIter, frIter + byteWidth_, expData)) {
488 "Bad value at index %" PRIu32
". count=%" PRIu32
", size=%" PRIu32,
491 (size / byteWidth_) - 1);
493 for (x = 0; x < byteWidth_; x++) {
496 "\n %" PRIu32
":%" PRIu32
" Got=0x%" PRIx8
" Exp=0x%" PRIx8,
501 snprintf(debugA + strlen(debugA),
sizeof(debugA) - strlen(debugA),
"%s", debugB);
503 rxLog_->warning(debugA);
507 frIter += byteWidth_;
515 if ((per = updateTime(&lastRxTime_)) > 0.0) {
516 rxRate_ =
static_cast<double>(rxCount_ - lastRxCount_) / per;
517 rxBw_ =
static_cast<double>(rxBytes_ - lastRxBytes_) / per;
518 lastRxCount_ = rxCount_;
519 lastRxBytes_ = rxBytes_;
523void ru::Prbs::setup_python() {
528 bp::docstring_options doc_options(
true,
false,
false);
530 bp::class_<ru::Prbs, ru::PrbsPtr, bp::bases<ris::Master, ris::Slave>, boost::noncopyable>(
532 "PRBS generator/checker that can act as both stream master and slave.\n\n"
533 "The engine can generate deterministic pseudo-random frames and verify\n"
534 "received frames for bit-error testing. It supports both one-shot frame\n"
535 "generation and optional background transmit mode.",
536 bp::init<>(
"Construct a PRBS generator/checker with default taps and width."))
537 .def(
"genFrame", &ru::Prbs::genFrame, bp::args(
"size"),
"Generate and transmit one PRBS frame.")
541 "Enable periodic background PRBS frame generation using the configured TX period.")
542 .def(
"disable", &ru::Prbs::disable,
"Disable periodic background PRBS frame generation.")
543 .def(
"setWidth", &ru::Prbs::setWidth, bp::args(
"width"),
"Set the PRBS generator/checker width in bits.")
545 &ru::Prbs::setTapsPy,
547 "Configure the PRBS LFSR tap positions from a bytes-like object.")
548 .def(
"getRxEnable", &ru::Prbs::getRxEnable,
"Return whether receive-side checking is enabled.")
549 .def(
"setRxEnable", &ru::Prbs::setRxEnable, bp::args(
"state"),
"Enable or disable receive-side checking.")
550 .def(
"getRxErrors", &ru::Prbs::getRxErrors,
"Return the receive-side error count.")
551 .def(
"getRxCount", &ru::Prbs::getRxCount,
"Return the total received frame count.")
552 .def(
"getRxRate", &ru::Prbs::getRxRate,
"Return the computed receive frame rate in frames/second.")
553 .def(
"getRxBw", &ru::Prbs::getRxBw,
"Return the computed receive bandwidth in bytes/second.")
554 .def(
"getRxBytes", &ru::Prbs::getRxBytes,
"Return the total received payload byte count.")
555 .def(
"getTxErrors", &ru::Prbs::getTxErrors,
"Return the transmit-side error count.")
556 .def(
"getTxCount", &ru::Prbs::getTxCount,
"Return the total transmitted frame count.")
557 .def(
"getTxBytes", &ru::Prbs::getTxBytes,
"Return the total transmitted payload byte count.")
558 .def(
"getTxPeriod", &ru::Prbs::getTxPeriod,
"Return the periodic transmit interval in microseconds.")
560 &ru::Prbs::setTxPeriod,
562 "Set the periodic transmit interval in microseconds.")
563 .def(
"getTxRate", &ru::Prbs::getTxRate,
"Return the computed transmit frame rate in frames/second.")
564 .def(
"getTxBw", &ru::Prbs::getTxBw,
"Return the computed transmit bandwidth in bytes/second.")
566 &ru::Prbs::checkPayload,
568 "Enable or disable PRBS payload checking on received frames.")
570 &ru::Prbs::genPayload,
572 "Enable or disable PRBS payload generation on transmitted frames.")
573 .def(
"resetCount", &ru::Prbs::resetCount,
"Reset transmit and receive counters.")
575 &ru::Prbs::sendCount,
577 "Enable or disable insertion of frame counters into generated payloads.");
579 bp::implicitly_convertible<ru::PrbsPtr, ris::SlavePtr>();
580 bp::implicitly_convertible<ru::PrbsPtr, ris::MasterPtr>();
Generic Rogue exception type.
RAII helper that releases the Python GIL for a scope.
static std::shared_ptr< rogue::Logging > create(const std::string &name, bool quiet=false)
Creates a logger instance.
Random-access byte iterator across a Frame payload.
static void fromFrame(rogue::interfaces::stream::FrameIterator &iter, uint32_t size, void *dst)
Copies bytes from a frame iterator to a destination pointer.
std::shared_ptr< rogue::interfaces::stream::Frame > FramePtr
Shared pointer alias for Frame.
static void toFrame(rogue::interfaces::stream::FrameIterator &iter, uint32_t size, void *src)
Copies bytes from a source pointer into a frame iterator.
std::shared_ptr< rogue::interfaces::stream::FrameLock > FrameLockPtr
Shared pointer alias for FrameLock.
std::shared_ptr< rogue::utilities::Prbs > PrbsPtr