w11 - cpp 0.794
Backend server for Rlink and w11
Loading...
Searching...
No Matches
RlinkPortCuff.cpp
Go to the documentation of this file.
1// $Id: RlinkPortCuff.cpp 1209 2021-08-22 13:17:33Z mueller $
2// SPDX-License-Identifier: GPL-3.0-or-later
3// Copyright 2012-2021 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4//
5// Revision History:
6// Date Rev Version Comment
7// 2021-08-17 1209 1.1.11 drop libusb_set_debug (now deprecated)
8// 2018-12-18 1089 1.1.10 use c++ style casts
9// 2018-12-17 1088 1.1.9 use std::thread instead of boost
10// 2018-12-14 1081 1.1.8 use std::bind instead of boost
11// 2018-11-09 1066 1.1.7 use auto
12// 2018-10-27 1059 1.1.6 coverity fixup (uncaught exception in dtor)
13// 2017-04-15 875 1.1.5 Open(): set default scheme
14// 2017-03-04 858 1.1.4 use clock_gettime instead of gettimeofday
15// 2015-04-12 666 1.1.3 add noinit attribute
16// 2014-08-22 584 1.1.2 use nullptr
17// 2013-05-17 521 1.1.1 use Rtools::String2Long
18// 2013-02-23 492 1.1 use RparseUrl
19// 2013-02-10 485 1.0.3 add static const defs
20// 2013-02-03 481 1.0.2 use Rexception
21// 2013-01-02 467 1.0.1 get cleanup code right; add USBErrorName()
22// 2012-12-26 465 1.0 Initial version
23// ---------------------------------------------------------------------------
24
29#include <errno.h>
30#include <unistd.h>
31#include <time.h>
32#include <stdio.h>
33#include <string.h>
34
35#include <iostream>
36#include <sstream>
37
38#include "RlinkPortCuff.hpp"
39
41#include "librtools/Rtools.hpp"
42
43using namespace std;
44
50// all method definitions in namespace Retro
51namespace Retro {
52
53//------------------------------------------+-----------------------------------
54// constants definitions
55
60
61//------------------------------------------+-----------------------------------
63
65 : RlinkPort(),
66 fFdReadDriver(-1),
67 fFdWriteDriver(-1),
68 fpUsbContext(nullptr),
69 fpUsbDevList(nullptr),
70 fUsbDevCount(0),
71 fpUsbDevHdl(nullptr),
72 fLoopState(kLoopStateStopped)
73{
74 fStats.Define(kStatNPollAddCB, "kStatNPollAddCB", "USB poll add cb");
75 fStats.Define(kStatNPollRemoveCB, "kStatNPollRemoveCB", "USB poll remove cb");
76 fStats.Define(kStatNUSBWrite, "kStatNUSBWrite", "USB write done");
77 fStats.Define(kStatNUSBRead, "kStatNUSBRead", "USB read done");
78}
79
80//------------------------------------------+-----------------------------------
82
84{
85 if (IsOpen()) Rtools::Catch2Cerr(__func__,
86 [this](){ RlinkPortCuff::Close(); } );
87}
88
89//------------------------------------------+-----------------------------------
91
92bool RlinkPortCuff::Open(const std::string& url, RerrMsg& emsg)
93{
94 int irc;
95
96 if (IsOpen()) Close();
97
98 if (!fUrl.Set(url, "|trace|noinit|", "cuff", emsg)) return false;
99
100 // initialize USB context
101 irc = libusb_init(&fpUsbContext);
102 if (irc != 0) {
103 emsg.Init("RlinkPortCuff::Open()",
104 string("libusb_init() failed: ") +
105 string(USBErrorName(irc)));
106 Cleanup();
107 return false;
108 }
109 //libusb_set_debug is deprecated, libusb_set_option has different features
110 //libusb_set_debug(fpUsbContext, 3); // info->stdout, warn+err->stderr
111
112 // check for internal timeout handling support
113 if (libusb_pollfds_handle_timeouts(fpUsbContext) == 0) {
114 emsg.Init("RlinkPortCuff::Open()",
115 string("libusb_pollfds_handle_timeouts == 0 : "
116 "this program will not run on this legacy system"));
117 Cleanup();
118 return false;
119 }
120
121 // get USB device list
122 fUsbDevCount = libusb_get_device_list(fpUsbContext, &fpUsbDevList);
123
124 // determine USB path name
125 if (fUrl.Path().length() == 0) {
126 char* env_vid = ::getenv("RETRO_FX2_VID");
127 char* env_pid = ::getenv("RETRO_FX2_PID");
128 if (env_vid && ::strlen(env_vid) == 4 &&
129 env_pid && ::strlen(env_pid) == 4) {
130 fUrl.SetPath(string(env_vid) + ":" + string(env_pid));
131 } else {
132 emsg.Init("RlinkPortCuff::Open()",
133 "RETRO_FX2_VID/PID not or ill defined");
134 Cleanup();
135 return false;
136 }
137 }
138
139 // connect to USB device
140 libusb_device* mydev = nullptr;
141 // path syntax: /bus/dev
142 if (fUrl.Path().length()==8 && fUrl.Path()[0]=='/' && fUrl.Path()[4]=='/') {
143 string busnam = fUrl.Path().substr(1,3);
144 string devnam = fUrl.Path().substr(5,3);
145 unsigned long busnum;
146 unsigned long devnum;
147 if (!Rtools::String2Long(busnam, busnum, emsg) ||
148 !Rtools::String2Long(devnam, devnum, emsg)) {
149 Cleanup();
150 return false;
151 }
152 for (ssize_t idev=0; idev<fUsbDevCount; idev++) {
153 libusb_device* udev = fpUsbDevList[idev];
154 if (libusb_get_bus_number(udev) == busnum &&
155 libusb_get_device_address(udev) == devnum) {
156 mydev = udev;
157 }
158 }
159 // path syntax: vend:prod
160 } else if (fUrl.Path().length()==9 && fUrl.Path()[4]==':') {
161 string vennam = fUrl.Path().substr(0,4);
162 string pronam = fUrl.Path().substr(5,4);
163 unsigned long vennum;
164 unsigned long pronum;
165 if (!Rtools::String2Long(vennam, vennum, emsg, 16) ||
166 !Rtools::String2Long(pronam, pronum, emsg, 16)) {
167 Cleanup();
168 return false;
169 }
170 for (ssize_t idev=0; idev<fUsbDevCount; idev++) {
171 libusb_device* udev = fpUsbDevList[idev];
172 libusb_device_descriptor devdsc;
173 libusb_get_device_descriptor(udev, &devdsc);
174 if (devdsc.idVendor==vennum && devdsc.idProduct==pronum) {
175 mydev = udev;
176 }
177 }
178 } else {
179 emsg.Init("RlinkPortCuff::Open()",
180 string("invalid usb path '") + fUrl.Path() +
181 "', not '/bus/dev' or 'vend:prod'");
182 Cleanup();
183 return false;
184 }
185
186 if (mydev == nullptr) {
187 emsg.Init("RlinkPortCuff::Open()",
188 string("no usb device '") + fUrl.Path() + "', found'");
189 Cleanup();
190 return false;
191 }
192
193 irc = libusb_open(mydev, &fpUsbDevHdl);
194 if (irc) {
195 fpUsbDevHdl = nullptr;
196 emsg.Init("RlinkPortCuff::Open()",
197 string("opening usb device '") + fUrl.Path() + "', failed: " +
198 string(USBErrorName(irc)));
199 Cleanup();
200 return false;
201 }
202 if (TraceOn()) cout << "libusb_open ok for '" << fUrl.Path() << "'" << endl;
203
204 // claim USB device
205 irc = libusb_claim_interface(fpUsbDevHdl, 0);
206 if (irc) {
207 emsg.Init("RlinkPortCuff::Open()",
208 string("failed to claim '") + fUrl.Path() + "': " +
209 string(USBErrorName(irc)));
210 Cleanup();
211 return false;
212 }
213
214 // setup write pipe
215 if (!OpenPipe(fFdWriteDriver, fFdWrite, emsg)) {
216 Cleanup();
217 return false;
218 }
219 // setup read pipe
220 if (!OpenPipe(fFdRead, fFdReadDriver, emsg)) {
221 Cleanup();
222 return false;
223 }
224
225 // setup pollfd list
226 fPollFds.clear();
227
228 // 1. write pipe allert (is always 1st in list)
229 PollfdAdd(fFdWriteDriver, POLLIN);
230
231 // 2. libusb callbacks
232 const libusb_pollfd** plist = libusb_get_pollfds(fpUsbContext);
233 for (auto p = plist; *p !=0; p++) {
234 PollfdAdd((*p)->fd, (*p)->events);
235 }
236 ::free(plist);
237 libusb_set_pollfd_notifiers(fpUsbContext, ThunkPollfdAdd,
238 ThunkPollfdRemove, this);
239
240 fDriverThread = thread([this](){ Driver(); });
241
242 fIsOpen = true;
243
244 return true;
245}
246
247//------------------------------------------+-----------------------------------
249
251{
252 if (!IsOpen()) return;
253
254 if (TraceOn()) cout << "Close() started" << endl;
255 Cleanup();
257
258 if (TraceOn()) cout << "Close() ended" << endl;
259 return;
260}
261
262//------------------------------------------+-----------------------------------
264
266{
267 // close write pipe from user side -> causes event in driver and driver stop
269
270 // wait till driver thread terminates
271 if (fDriverThread.joinable()) fDriverThread.join();
272
273 // cleanup pipes
277
278 // cleanup USB context
279 if (fpUsbContext) {
280 if (fpUsbDevHdl) {
281 libusb_release_interface(fpUsbDevHdl, 0);
282 libusb_close(fpUsbDevHdl);
283 fpUsbDevHdl = nullptr;
284 }
285 if (fpUsbDevList) {
286 libusb_free_device_list(fpUsbDevList, 1);
287 fpUsbDevList = nullptr;
288 }
289 libusb_set_pollfd_notifiers(fpUsbContext, nullptr, nullptr, nullptr);
290 libusb_exit(fpUsbContext);
291 fpUsbContext = nullptr;
292 }
293
294 fPollFds.clear();
295
296 return;
297}
298
299//------------------------------------------+-----------------------------------
301
302bool RlinkPortCuff::OpenPipe(int& fdread, int& fdwrite, RerrMsg& emsg)
303{
304 int irc;
305 int pipefd[2];
306
307 irc = ::pipe(pipefd);
308 if (irc < 0) {
309 emsg.InitErrno("RlinkPortCuff::OpenPipe()", "pipe() failed: ", errno);
310 return false;
311 }
312
313 fdread = pipefd[0];
314 fdwrite = pipefd[1];
315
316 return true;
317}
318
319//------------------------------------------+-----------------------------------
321
322// executed in separate thread !!
324{
325 try {
326
327 // setup USB read-ahead queue
328 for (size_t nr=0; nr<kUSBReadQueue; nr++) {
329 libusb_transfer* t = libusb_alloc_transfer(0);
330
331 t->dev_handle = fpUsbDevHdl;
332 t->flags = LIBUSB_TRANSFER_FREE_BUFFER;
333 t->endpoint = static_cast<unsigned char>(kUSBReadEP|0x80);
334 t->type = LIBUSB_TRANSFER_TYPE_BULK;
335 t->timeout = 0;
336 t->status = LIBUSB_TRANSFER_COMPLETED;
337 t->buffer = reinterpret_cast<unsigned char*>(::malloc(kUSBBufferSize));
338 t->length = kUSBBufferSize;
339 t->actual_length = 0;
340 t->callback = ThunkUSBReadDone;
341 t->user_data = this;
342
343 int irc = libusb_submit_transfer(t);
344 if (irc) BadUSBCall("RlinkPortCuff::Driver()",
345 "libusb_submit_transfer()", irc);
346 fReadQueuePending.push_back(t);
347 }
348
349 // event loop
350 if (TraceOn()) cout << "event loop started" << endl;
352 while(fLoopState == kLoopStateRunning) {
353 int irc = ::poll(fPollFds.data(), fPollFds.size(), 1000);
354 if (irc==-1 && errno==EINTR) continue;
355 if (irc!=0 && TraceOn()) {
356 cout << "poll() -> " << irc << " :";
357 for (size_t i=0; i<fPollFds.size(); i++)
358 if (fPollFds[i].revents) cout << " (" << fPollFds[i].fd << ","
359 << fPollFds[i].events << ","
360 << fPollFds[i].revents << ")";
361 cout << endl;
362 }
363
364 if (irc < 0) BadSysCall("RlinkPortCuff::Driver()", "poll()", irc);
365
366 if (fPollFds[0].revents & POLLHUP) { // write pipe close event
368 } else if (fPollFds[0].revents & POLLIN) { // write pipe data event
370 } else { // assume USB timeout events
372 }
373 }
374
375 if (TraceOn()) cout << "event loop ended, cleanup started" << endl;
376
377 for (size_t i=0; i<fWriteQueuePending.size(); i++) {
378 libusb_cancel_transfer(fWriteQueuePending[i]);
379 }
380 for (size_t i=0; i<fReadQueuePending.size(); i++) {
381 libusb_cancel_transfer(fReadQueuePending[i]);
382 }
383
385 fWriteQueuePending.size() + fReadQueuePending.size() > 0) {
386 int irc = ::poll(fPollFds.data()+1, fPollFds.size()-1, 1000);
387 if (irc==-1 && errno==EINTR) continue;
388 if (irc==0) break;
389 if (irc < 0) BadSysCall("RlinkPortCuff::Driver()", "poll()", irc);
391 }
392 if (fWriteQueuePending.size() + fReadQueuePending.size())
393 throw Rexception("RlinkPortCuff::Driver()", "cleanup timeout");
394
396 if (TraceOn()) cout << "cleanup ended" << endl;
397
398 } catch (exception& e) {
399 cout << "exception caught in RlinkPortCuff::Driver(): '" << e.what()
400 << "'" << endl;
401 // close read pipe at driver end -> that causes main thread to respond
402 ::close(fFdReadDriver);
403 fFdReadDriver = -1;
404 }
405
406 return;
407}
408
409//------------------------------------------+-----------------------------------
411
413{
414 libusb_transfer* t = NewWriteTransfer();
415
416 ssize_t ircs = ::read(fFdWriteDriver, t->buffer, kUSBBufferSize);
417 if (TraceOn()) cout << "write pipe read() -> " << ircs << endl;
418 if (ircs < 0) BadSysCall("RlinkPortCuff::DriverEventWritePipe()",
419 "read()", ircs);
420
421 // pipe closed... end driver event loop
422 if (ircs == 0) {
424 return;
425 }
426
427 t->length = int(ircs);
428 int irc = libusb_submit_transfer(t);
429 if (irc) BadUSBCall("RlinkPortCuff::DriverEventWritePipe()",
430 "libusb_submit_transfer()", irc);
431 fWriteQueuePending.push_back(t);
432
433 return;
434}
435
436//------------------------------------------+-----------------------------------
438
440{
441 struct timeval tv;
442 tv.tv_sec = 0;
443 tv.tv_usec = 0;
444 int irc = libusb_handle_events_timeout(fpUsbContext, &tv);
445 //setting the timeval pointer to nullptr should work, but doesn't (in 1.0.6)
446 //rc = libusb_handle_events_timeout(pUsbContext, 0);
447 if (irc) BadUSBCall("RlinkPortCuff::DriverEventUSB()",
448 "libusb_handle_events_timeout()", irc);
449 return;
450}
451
452//------------------------------------------+-----------------------------------
454
456{
457 libusb_transfer* t = nullptr;
458 if (!fWriteQueueFree.empty()) {
459 t = fWriteQueueFree.front();
460 fWriteQueueFree.pop_front();
461 } else {
462 t = libusb_alloc_transfer(0);
463 t->dev_handle = fpUsbDevHdl;
464 t->flags = LIBUSB_TRANSFER_FREE_BUFFER;
465 t->endpoint = static_cast<unsigned char>(kUSBWriteEP);
466 t->type = LIBUSB_TRANSFER_TYPE_BULK;
467 t->timeout = 1000;
468 t->buffer = reinterpret_cast<unsigned char*>(::malloc(kUSBBufferSize));
469 t->callback = ThunkUSBWriteDone;
470 t->user_data = this;
471 }
472
473 t->status = LIBUSB_TRANSFER_COMPLETED;
474 t->length = 0;
475 t->actual_length = 0;
476
477 return t;
478}
479
480//------------------------------------------+-----------------------------------
482
484{
485 if (!fUrl.FindOpt("trace")) return false;
486 struct timespec ts;
487 struct tm tmval;
488
489 ::clock_gettime(CLOCK_REALTIME, &ts);
490 ::localtime_r(&ts.tv_sec, &tmval);
491 char buf[20];
492 ::snprintf(buf, 20, "%02d:%02d:%02d.%06d: ",
493 tmval.tm_hour, tmval.tm_min, tmval.tm_sec, int(ts.tv_nsec)/1000);
494 cout << buf;
495 return true;
496}
497
498//------------------------------------------+-----------------------------------
500
501[[noreturn]]
502void RlinkPortCuff::BadSysCall(const char* meth, const char* text, int rc)
503{
504 stringstream ss;
505 ss << rc;
506 throw Rexception(meth, string(text) + " failed with rc=" + ss.str(),
507 errno);
508}
509
510//------------------------------------------+-----------------------------------
512
513[[noreturn]]
514void RlinkPortCuff::BadUSBCall(const char* meth, const char* text, int rc)
515{
516 stringstream ss;
517 ss << rc;
518 throw Rexception(meth, string(text) + " failed with rc=" + ss.str() +
519 " : " + string(USBErrorName(rc)));
520}
521
522//------------------------------------------+-----------------------------------
524
525void RlinkPortCuff::CheckUSBTransfer(const char* meth, libusb_transfer *t)
526{
527 const char* etext = nullptr;
528
529 if (t->status == LIBUSB_TRANSFER_ERROR) etext = "ERROR";
530 if (t->status == LIBUSB_TRANSFER_STALL) etext = "STALL";
531 if (t->status == LIBUSB_TRANSFER_NO_DEVICE) etext = "NO_DEVICE";
532 if (t->status == LIBUSB_TRANSFER_OVERFLOW) etext = "OVERFLOW";
533
534 if (etext == 0) return;
535
536 char buf[1024];
537 ::snprintf(buf, 1024, "%s : transfer failure on ep=%d: %s",
538 meth, int(t->endpoint&(~0x80)), etext);
539 throw Rexception(meth, buf);
540}
541
542//------------------------------------------+-----------------------------------
544
546{
547 // Code taken verbatim from libusb-1.0.9.tar.bz2 function libusb_error_name
548 // The libusb_error_name() function was added rather late in V1.0.9.
549 // To allow usage with V1.0.8 and earlier this function is include here
550
551 switch (rc) {
552 case LIBUSB_SUCCESS:
553 return "LIBUSB_SUCCESS";
554 case LIBUSB_ERROR_IO:
555 return "LIBUSB_ERROR_IO";
556 case LIBUSB_ERROR_INVALID_PARAM:
557 return "LIBUSB_ERROR_INVALID_PARAM";
558 case LIBUSB_ERROR_ACCESS:
559 return "LIBUSB_ERROR_ACCESS";
560 case LIBUSB_ERROR_NO_DEVICE:
561 return "LIBUSB_ERROR_NO_DEVICE";
562 case LIBUSB_ERROR_NOT_FOUND:
563 return "LIBUSB_ERROR_NOT_FOUND";
564 case LIBUSB_ERROR_BUSY:
565 return "LIBUSB_ERROR_BUSY";
566 case LIBUSB_ERROR_TIMEOUT:
567 return "LIBUSB_ERROR_TIMEOUT";
568 case LIBUSB_ERROR_OVERFLOW:
569 return "LIBUSB_ERROR_OVERFLOW";
570 case LIBUSB_ERROR_PIPE:
571 return "LIBUSB_ERROR_PIPE";
572 case LIBUSB_ERROR_INTERRUPTED:
573 return "LIBUSB_ERROR_INTERRUPTED";
574 case LIBUSB_ERROR_NO_MEM:
575 return "LIBUSB_ERROR_NO_MEM";
576 case LIBUSB_ERROR_NOT_SUPPORTED:
577 return "LIBUSB_ERROR_NOT_SUPPORTED";
578 case LIBUSB_ERROR_OTHER:
579 return "LIBUSB_ERROR_OTHER";
580 }
581 return "**UNKNOWN**";
582}
583
584//------------------------------------------+-----------------------------------
586
587void RlinkPortCuff::PollfdAdd(int fd, short events)
588{
590 pollfd pfd;
591 pfd.fd = fd;
592 pfd.events = events;
593 pfd.revents = 0;
594 fPollFds.push_back(pfd);
595 return;
596}
597
598//------------------------------------------+-----------------------------------
600
602{
604 for (size_t i=0; i<fPollFds.size(); ) {
605 if (fPollFds[i].fd == fd) {
606 fPollFds.erase(fPollFds.begin()+i);
607 } else {
608 i++;
609 }
610 }
611 return;
612}
613
614//------------------------------------------+-----------------------------------
616
617void RlinkPortCuff::USBWriteDone(libusb_transfer* t)
618{
619 if (TraceOn()) cout << "USB write done -> " << t->actual_length << endl;
620
621 if (fWriteQueuePending.size() && t == fWriteQueuePending.front())
622 fWriteQueuePending.pop_front();
623 else
624 throw Rexception("RlinkPortCuff::USBWriteDone()",
625 "BugCheck: fWriteQueuePending disordered");
626
628 CheckUSBTransfer("RlinkPortCuff::USBWriteDone()", t);
630 fWriteQueueFree.push_back(t);
631
632 } else {
633 libusb_free_transfer(t);
634 }
635 return;
636}
637
638//------------------------------------------+-----------------------------------
640
641void RlinkPortCuff::USBReadDone(libusb_transfer* t)
642{
643 if (TraceOn()) cout << "USB read done -> " << t->actual_length << endl;
644
645 if (fReadQueuePending.size() && t == fReadQueuePending.front())
646 fReadQueuePending.pop_front();
647 else
648 throw Rexception("RlinkPortCuff::USBReadDone()",
649 "BugCheck: fReadQueuePending disordered");
650
652 CheckUSBTransfer("RlinkPortCuff::USBReadDone()", t);
654 if (t->actual_length>0) {
655 ssize_t ircs = ::write(fFdReadDriver, t->buffer,
656 size_t(t->actual_length));
657 if (ircs < 0) BadSysCall("RlinkPortCuff::USBReadDone()",
658 "write()", ircs);
659 }
660
661 t->status = LIBUSB_TRANSFER_COMPLETED;
662 t->actual_length = 0;
663 int irc = libusb_submit_transfer(t);
664 if (irc) BadUSBCall("RlinkPortCuff::USBReadDone()",
665 "libusb_submit_transfer()", irc);
666 fReadQueuePending.push_back(t);
667
668 } else {
669 libusb_free_transfer(t);
670 }
671
672 return;
673}
674
675//------------------------------------------+-----------------------------------
677
678void RlinkPortCuff::ThunkPollfdAdd(int fd, short events, void* udata)
679{
680 RlinkPortCuff* pcntx = reinterpret_cast<RlinkPortCuff*>(udata);
681 pcntx->PollfdAdd(fd, events);
682 return;
683}
684
685//------------------------------------------+-----------------------------------
687
688void RlinkPortCuff::ThunkPollfdRemove(int fd, void* udata)
689{
690 RlinkPortCuff* pcntx = reinterpret_cast<RlinkPortCuff*>(udata);
691 pcntx->PollfdRemove(fd);
692 return;
693}
694
695//------------------------------------------+-----------------------------------
697
698void RlinkPortCuff::ThunkUSBWriteDone(libusb_transfer* t)
699{
700 RlinkPortCuff* pcntx = reinterpret_cast<RlinkPortCuff*>(t->user_data);
701 pcntx->USBWriteDone(t);
702 return;
703}
704
705//------------------------------------------+-----------------------------------
707
708void RlinkPortCuff::ThunkUSBReadDone(libusb_transfer* t)
709{
710 RlinkPortCuff* pcntx = reinterpret_cast<RlinkPortCuff*>(t->user_data);
711 pcntx->USBReadDone(t);
712 return;
713}
714
715} // end namespace Retro
FIXME_docs.
Definition: RerrMsg.hpp:25
void Init(const std::string &meth, const std::string &text)
FIXME_docs.
Definition: RerrMsg.cpp:74
void InitErrno(const std::string &meth, const std::string &text, int errnum)
FIXME_docs.
Definition: RerrMsg.cpp:84
FIXME_docs.
Definition: Rexception.hpp:29
static const int kUSBWriteEP
USB write endpoint.
void PollfdRemove(int fd)
FIXME_docs.
void Cleanup()
FIXME_docs.
int fFdWriteDriver
fd for write (driver end)
static void ThunkPollfdRemove(int fd, void *udata)
FIXME_docs.
virtual void Close()
FIXME_docs.
void Driver()
FIXME_docs.
void USBWriteDone(libusb_transfer *t)
FIXME_docs.
bool OpenPipe(int &fdread, int &fdwrite, RerrMsg &emsg)
FIXME_docs.
libusb_device_handle * fpUsbDevHdl
void DriverEventWritePipe()
FIXME_docs.
void BadUSBCall(const char *meth, const char *text, int rc)
FIXME_docs.
static const size_t kUSBBufferSize
USB buffer size.
void DriverEventUSB()
FIXME_docs.
const char * USBErrorName(int rc)
FIXME_docs.
bool TraceOn()
FIXME_docs.
void USBReadDone(libusb_transfer *t)
FIXME_docs.
void BadSysCall(const char *meth, const char *text, int rc)
FIXME_docs.
std::thread fDriverThread
driver thread
std::deque< libusb_transfer * > fReadQueuePending
std::vector< pollfd > fPollFds
void CheckUSBTransfer(const char *meth, libusb_transfer *t)
FIXME_docs.
std::deque< libusb_transfer * > fWriteQueueFree
RlinkPortCuff()
Default constructor.
virtual ~RlinkPortCuff()
Destructor.
void PollfdAdd(int fd, short events)
FIXME_docs.
libusb_context * fpUsbContext
static void ThunkPollfdAdd(int fd, short events, void *udata)
FIXME_docs.
libusb_device ** fpUsbDevList
static void ThunkUSBWriteDone(libusb_transfer *t)
FIXME_docs.
libusb_transfer * NewWriteTransfer()
FIXME_docs.
std::deque< libusb_transfer * > fWriteQueuePending
static void ThunkUSBReadDone(libusb_transfer *t)
FIXME_docs.
static const size_t kUSBReadQueue
USB read queue length.
static const int kUSBReadEP
USB read endpoint.
virtual bool Open(const std::string &url, RerrMsg &emsg)
FIXME_docs.
int fFdReadDriver
fd for read (driver end)
FIXME_docs.
Definition: RlinkPort.hpp:45
void CloseFd(int &fd)
FIXME_docs.
Definition: RlinkPort.cpp:310
int fFdWrite
fd for write
Definition: RlinkPort.hpp:109
bool IsOpen() const
FIXME_docs.
Definition: RlinkPort.ipp:27
RparseUrl fUrl
parsed url
Definition: RlinkPort.hpp:106
int fFdRead
fd for read
Definition: RlinkPort.hpp:108
bool fIsOpen
is open flag
Definition: RlinkPort.hpp:105
virtual void Close()
FIXME_docs.
Definition: RlinkPort.cpp:98
Rstats fStats
statistics
Definition: RlinkPort.hpp:114
bool FindOpt(const std::string &name) const
FIXME_docs.
Definition: RparseUrl.cpp:196
bool Set(const std::string &url, const std::string &optlist, RerrMsg &emsg)
FIXME_docs.
Definition: RparseUrl.cpp:55
void SetPath(const std::string &path)
FIXME_docs.
Definition: RparseUrl.ipp:20
const std::string & Path() const
FIXME_docs.
Definition: RparseUrl.ipp:45
void Inc(size_t ind, double val=1.)
FIXME_docs.
Definition: Rstats.ipp:29
void Define(size_t ind, const std::string &name, const std::string &text)
FIXME_docs.
Definition: Rstats.cpp:72
bool String2Long(const std::string &str, long &res, RerrMsg &emsg, int base)
FIXME_docs.
Definition: Rtools.cpp:67
void Catch2Cerr(const char *msg, std::function< void()> func)
FIXME_docs.
Definition: Rtools.cpp:170
Declaration of class ReventLoop.
Definition: ReventLoop.cpp:47