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);
107double ru::Prbs::updateTime(
struct timeval* last) {
116 gettimeofday(&now, NULL);
118 timersub(&now, last, &per);
120 if (timercmp(&per, &cmp, >)) {
121 ret =
static_cast<float>(per.tv_sec) +
static_cast<float>(per.tv_usec) / 1e6;
122 gettimeofday(last, NULL);
130void ru::Prbs::setWidth(uint32_t width) {
131 if ((width > (MaxBytes * 8)) || (width % 32) != 0)
throw(
rogue::GeneralError(
"Prbs::setWidth",
"Invalid width."));
134 std::lock_guard<std::mutex> lockT(pMtx_);
137 byteWidth_ = width / 8;
138 minSize_ = byteWidth_ * 3;
142void ru::Prbs::setTaps(uint32_t tapCnt, uint8_t* taps) {
145 std::lock_guard<std::mutex> lockT(pMtx_);
149 taps_ =
reinterpret_cast<uint8_t*
>(malloc(
sizeof(uint8_t) * tapCnt));
151 for (i = 0; i < tapCnt_; i++) taps_[i] = taps[i];
157void ru::Prbs::setTapsPy(boost::python::object p) {
160 if (PyObject_GetBuffer(p.ptr(), &pyBuf, PyBUF_SIMPLE) < 0)
163 setTaps(pyBuf.len,
reinterpret_cast<uint8_t*
>(pyBuf.buf));
164 PyBuffer_Release(&pyBuf);
170void ru::Prbs::sendCount(
bool state) {
172 std::lock_guard<std::mutex> lockT(pMtx_);
177void ru::Prbs::flfsr(uint8_t* data) {
184 for (x = 0; x < tapCnt_; x++) {
185 iByte = taps_[x] / 8;
187 lsbIn ^= ((data[iByte] >> iBit) & 0x1);
190 for (x = 0; x < byteWidth_; x++) {
191 msbOut = data[x] & 0x80;
199void ru::Prbs::runThread() {
200 txLog_->logThreadId();
204 if ( txPeriod_ > 0 ) usleep(txPeriod_);
209void ru::Prbs::enable(uint32_t size) {
211 if (((size % byteWidth_) != 0) || size < minSize_)
throw rogue::GeneralError(
"Prbs::enable",
"Invalid frame size");
213 if (txThread_ == NULL) {
216 txThread_ =
new std::thread(&Prbs::runThread,
this);
220 pthread_setname_np(txThread_->native_handle(),
"PrbsTx");
226void ru::Prbs::disable() {
227 if (txThread_ != NULL) {
237bool ru::Prbs::getRxEnable() {
242void ru::Prbs::setRxEnable(
bool en) {
250uint32_t ru::Prbs::getRxErrors() {
251 return (rxErrCount_);
255uint32_t ru::Prbs::getRxCount() {
260uint64_t ru::Prbs::getRxBytes() {
265uint32_t ru::Prbs::getTxErrors() {
266 return (txErrCount_);
270uint32_t ru::Prbs::getTxCount() {
275double ru::Prbs::getRxRate() {
280double ru::Prbs::getRxBw() {
285double ru::Prbs::getTxRate() {
290uint32_t ru::Prbs::getTxPeriod() {
295void ru::Prbs::setTxPeriod(uint32_t value) {
300double ru::Prbs::getTxBw() {
305uint64_t ru::Prbs::getTxBytes() {
310void ru::Prbs::checkPayload(
bool state) {
315void ru::Prbs::genPayload(
bool state) {
321void ru::Prbs::resetCount() {
333void ru::Prbs::genFrame(uint32_t size) {
336 uint32_t frSeq[MaxBytes / 4];
337 uint32_t frSize[MaxBytes / 4];
338 uint32_t wCount[MaxBytes / 4];
339 uint8_t data[MaxBytes];
344 std::lock_guard<std::mutex> lock(pMtx_);
347 if (((size % byteWidth_) != 0) || size < minSize_)
351 memset(frSize, 0, MaxBytes);
352 frSize[0] = (size / byteWidth_) - 1;
355 memset(frSeq, 0, MaxBytes);
359 memset(wCount, 0, MaxBytes);
362 fr = reqFrame(size,
true);
363 fr->setPayload(size);
365 frIter = fr->begin();
366 frEnd = frIter + size;
378 std::memcpy(data, frSeq, byteWidth_);
381 while (frIter != frEnd) {
399 if ((per = updateTime(&lastTxTime_)) > 0.0) {
400 txRate_ =
static_cast<double>(txCount_ - lastTxCount_) / per;
401 txBw_ =
static_cast<double>(txBytes_ - lastTxBytes_) / per;
402 lastTxCount_ = txCount_;
403 lastTxBytes_ = txBytes_;
411 uint32_t frSeq[MaxBytes / 4];
412 uint32_t frSize[MaxBytes / 4];
418 uint8_t expData[MaxBytes];
425 while (!rxEnable_) usleep(10000);
428 std::lock_guard<std::mutex> lock(pMtx_);
430 size = frame->getPayload();
431 frIter = frame->begin();
432 frEnd = frame->end();
435 if (frame->getError()) {
436 rxLog_->warning(
"Frame error field is set: 0x%" PRIx8, frame->getError());
442 if (((size % byteWidth_) != 0) || size < minSize_) {
443 rxLog_->warning(
"Size violation size=%" PRIu32
", count=%" PRIu32, size, rxCount_);
451 rxSeq_ = frSeq[0] + 1;
455 expSize = (frSize[0] + 1) * byteWidth_;
460 if ((expSize != size) || (frSeq[0] != 0 && expSeq != 0 && frSeq[0] != expSeq)) {
461 rxLog_->warning(
"Bad header. expSize=%" PRIu32
" gotSize=%" PRIu32
" expSeq=%" PRIu32
" gotSeq=%" PRIu32
462 " nxtSeq=%" PRIu32
" count=%" PRIu32,
476 std::memcpy(expData, frSeq, byteWidth_);
480 while (frIter != frEnd) {
483 if (!std::equal(frIter, frIter + byteWidth_, expData)) {
486 "Bad value at index %" PRIu32
". count=%" PRIu32
", size=%" PRIu32,
489 (size / byteWidth_) - 1);
491 for (x = 0; x < byteWidth_; x++) {
494 "\n %" PRIu32
":%" PRIu32
" Got=0x%" PRIx8
" Exp=0x%" PRIx8,
499 snprintf(debugA + strlen(debugA),
sizeof(debugA) - strlen(debugA),
"%s", debugB);
501 rxLog_->warning(debugA);
505 frIter += byteWidth_;
513 if ((per = updateTime(&lastRxTime_)) > 0.0) {
514 rxRate_ =
static_cast<double>(rxCount_ - lastRxCount_) / per;
515 rxBw_ =
static_cast<double>(rxBytes_ - lastRxBytes_) / per;
516 lastRxCount_ = rxCount_;
517 lastRxBytes_ = rxBytes_;
521void ru::Prbs::setup_python() {
526 bp::docstring_options doc_options(
true,
false,
false);
528 bp::class_<ru::Prbs, ru::PrbsPtr, bp::bases<ris::Master, ris::Slave>, boost::noncopyable>(
530 "PRBS generator/checker that can act as both stream master and slave.\n\n"
531 "The engine can generate deterministic pseudo-random frames and verify\n"
532 "received frames for bit-error testing. It supports both one-shot frame\n"
533 "generation and optional background transmit mode.",
534 bp::init<>(
"Construct a PRBS generator/checker with default taps and width."))
535 .def(
"genFrame", &ru::Prbs::genFrame, bp::args(
"size"),
"Generate and transmit one PRBS frame.")
539 "Enable periodic background PRBS frame generation using the configured TX period.")
540 .def(
"disable", &ru::Prbs::disable,
"Disable periodic background PRBS frame generation.")
541 .def(
"setWidth", &ru::Prbs::setWidth, bp::args(
"width"),
"Set the PRBS generator/checker width in bits.")
543 &ru::Prbs::setTapsPy,
545 "Configure the PRBS LFSR tap positions from a bytes-like object.")
546 .def(
"getRxEnable", &ru::Prbs::getRxEnable,
"Return whether receive-side checking is enabled.")
547 .def(
"setRxEnable", &ru::Prbs::setRxEnable, bp::args(
"state"),
"Enable or disable receive-side checking.")
548 .def(
"getRxErrors", &ru::Prbs::getRxErrors,
"Return the receive-side error count.")
549 .def(
"getRxCount", &ru::Prbs::getRxCount,
"Return the total received frame count.")
550 .def(
"getRxRate", &ru::Prbs::getRxRate,
"Return the computed receive frame rate in frames/second.")
551 .def(
"getRxBw", &ru::Prbs::getRxBw,
"Return the computed receive bandwidth in bytes/second.")
552 .def(
"getRxBytes", &ru::Prbs::getRxBytes,
"Return the total received payload byte count.")
553 .def(
"getTxErrors", &ru::Prbs::getTxErrors,
"Return the transmit-side error count.")
554 .def(
"getTxCount", &ru::Prbs::getTxCount,
"Return the total transmitted frame count.")
555 .def(
"getTxBytes", &ru::Prbs::getTxBytes,
"Return the total transmitted payload byte count.")
556 .def(
"getTxPeriod", &ru::Prbs::getTxPeriod,
"Return the periodic transmit interval in microseconds.")
558 &ru::Prbs::setTxPeriod,
560 "Set the periodic transmit interval in microseconds.")
561 .def(
"getTxRate", &ru::Prbs::getTxRate,
"Return the computed transmit frame rate in frames/second.")
562 .def(
"getTxBw", &ru::Prbs::getTxBw,
"Return the computed transmit bandwidth in bytes/second.")
564 &ru::Prbs::checkPayload,
566 "Enable or disable PRBS payload checking on received frames.")
568 &ru::Prbs::genPayload,
570 "Enable or disable PRBS payload generation on transmitted frames.")
571 .def(
"resetCount", &ru::Prbs::resetCount,
"Reset transmit and receive counters.")
573 &ru::Prbs::sendCount,
575 "Enable or disable insertion of frame counters into generated payloads.");
577 bp::implicitly_convertible<ru::PrbsPtr, ris::SlavePtr>();
578 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