47 #include <boost/python.hpp>
48namespace bp = boost::python;
58rpx::Xvc::Xvc(uint16_t port) :
JtagDriver(port), mtu_(1450), threadEn_{false}, started_{false} {
71 strerror(errno), errno));
72 if (::fcntl(
wakeFd_[0], F_SETFL, O_NONBLOCK) < 0 ||
73 ::fcntl(
wakeFd_[1], F_SETFL, O_NONBLOCK) < 0 ||
74 ::fcntl(
wakeFd_[0], F_SETFD, FD_CLOEXEC) < 0 ||
75 ::fcntl(
wakeFd_[1], F_SETFD, FD_CLOEXEC) < 0) {
84 if (::pipe2(
wakeFd_, O_NONBLOCK | O_CLOEXEC) < 0)
86 strerror(errno), errno));
96 if (threadEn_.load(std::memory_order_acquire)) {
101 if (wakeFd_[0] >= 0) {
105 if (wakeFd_[1] >= 0) {
112void rpx::Xvc::start() {
121 xvcLog_->debug(
"Starting the XVC server thread");
127 if (started_.load(std::memory_order_acquire))
135 unsigned maxMsg = 32768;
136 server_ = std::make_unique<rpx::XvcServer>(port_, wakeFd_[0],
this, maxMsg);
137 boundPort_.store(server_->getPort(), std::memory_order_release);
141 threadEn_.store(
true, std::memory_order_release);
143 thread_ = std::make_unique<std::thread>(&rpx::Xvc::runThread,
this);
145 threadEn_.store(
false, std::memory_order_release);
146 boundPort_.store(0, std::memory_order_release);
152 started_.store(
true, std::memory_order_release);
160#if defined(__linux__)
161 pthread_setname_np(thread_->native_handle(),
"XvcServer");
162#elif defined(__APPLE__)
169void rpx::Xvc::stop() {
181 if (!started_.load(std::memory_order_acquire))
return;
184 xvcLog_->debug(
"Stopping the XVC server thread");
191 done_.store(
true, std::memory_order_release);
202 if (wakeFd_[1] >= 0) {
205 w = ::write(wakeFd_[1],
"x", 1);
206 }
while (w < 0 && errno == EINTR);
211 if (threadEn_.exchange(
false, std::memory_order_acq_rel)) {
220 boundPort_.store(0, std::memory_order_release);
224void rpx::Xvc::runThread() {
225#if defined(__APPLE__)
228 pthread_setname_np(
"XvcServer");
257 std::unique_ptr<rogue::ScopedGil> threadGil;
258 if (Py_IsInitialized()) threadGil = std::make_unique<rogue::ScopedGil>();
274 if (server_) server_->run(threadEn_, xvcLog_);
275 }
catch (
const std::exception& e) {
276 if (xvcLog_) xvcLog_->warning(
"XVC server thread exiting on exception: %s", e.what());
277 done_.store(
true, std::memory_order_release);
281 if (xvcLog_) xvcLog_->warning(
"XVC server thread exiting on unknown exception");
282 done_.store(
true, std::memory_order_release);
291 if (!queue_.busy()) queue_.push(frame);
299uint64_t rpx::Xvc::getMaxVectorSize() {
301 unsigned ws = getWordSize();
302 if (ws >= mtu_)
return 0;
303 uint64_t mtuLim = (mtu_ - ws) / 2;
308uint32_t rpx::Xvc::getPort()
const {
309 uint32_t p = boundPort_.load(std::memory_order_acquire);
310 return p ? p :
static_cast<uint32_t
>(port_);
313int rpx::Xvc::xfer(uint8_t* txBuffer,
320 if (!threadEn_.load(std::memory_order_acquire))
return 0;
353 xvcLog_->debug(
"Tx buffer has %" PRIu32
" bytes to send",
static_cast<uint32_t
>(txBytes));
355 txFrame = reqFrame(
static_cast<uint32_t
>(txBytes),
true);
356 txFrame->setPayload(
static_cast<uint32_t
>(txBytes));
358 ris::toFrame(iter,
static_cast<uint32_t
>(txBytes), txBuffer);
360 xvcLog_->debug(
"Sending new frame of size %" PRIu32, txFrame->getSize());
361 if (txBytes) sendFrame(txFrame);
367 rxFrame = queue_.pop();
368 if (!rxFrame)
return 0;
370 xvcLog_->debug(
"Receiving new frame of size %" PRIu32, rxFrame->getSize());
375 std::lock_guard<std::mutex> lock(mtx_);
377 const uint32_t payload = rxFrame->getPayload();
378 if (payload <
static_cast<uint32_t
>(hdBytes)) {
379 if (hdBuffer && hdBytes) std::memset(hdBuffer, 0, hdBytes);
380 xvcLog_->error(
"Rx frame payload %" PRIu32
" smaller than header size %u", payload, hdBytes);
382 "Rx frame payload smaller than header size");
384 const uint32_t rxPayload = payload -
static_cast<uint32_t
>(hdBytes);
385 const uint32_t rxCopy = (rxPayload >
static_cast<uint32_t
>(rxBytes))
386 ?
static_cast<uint32_t
>(rxBytes)
389 iter = rxFrame->begin();
390 if (hdBuffer && hdBytes) std::copy(iter, iter +
static_cast<ptrdiff_t
>(hdBytes), hdBuffer);
391 iter +=
static_cast<ptrdiff_t
>(hdBytes);
394 if (rxCopy >
static_cast<uint32_t
>(INT_MAX))
396 "Rx payload size exceeds int return range");
397 return static_cast<int>(rxCopy);
403void rpx::Xvc::setup_python() {
406 bp::class_<rpx::Xvc, rpx::XvcPtr, bp::bases<ris::Master, ris::Slave, rpx::JtagDriver>, boost::noncopyable>(
408 bp::init<uint16_t>())
409 .def(
"_start", &rpx::Xvc::start)
410 .def(
"_stop", &rpx::Xvc::stop)
411 .def(
"getPort", &rpx::Xvc::getPort);
412 bp::implicitly_convertible<rpx::XvcPtr, ris::MasterPtr>();
413 bp::implicitly_convertible<rpx::XvcPtr, ris::SlavePtr>();
414 bp::implicitly_convertible<rpx::XvcPtr, rpx::JtagDriverPtr>();
static GeneralError create(std::string src, const char *fmt,...)
Creates a formatted error instance.
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.
void setThold(uint32_t thold)
Sets busy-threshold depth used by busy().
Random-access byte iterator across a Frame payload.
Base transport driver for the AxisToJtag firmware protocol.
rogue::Queue< std::shared_ptr< rogue::interfaces::stream::Frame > > queue_
std::shared_ptr< rogue::Logging > xvcLog_
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::protocols::xilinx::Xvc > XvcPtr