00001
00002
00003
00004 #ifdef RS_USE_V4L2_BACKEND
00005
00006 #include "uvc.h"
00007
00008 #include <cassert>
00009 #include <cstdlib>
00010 #include <cstdio>
00011 #include <sstream>
00012 #include <cstring>
00013
00014 #include <algorithm>
00015 #include <functional>
00016 #include <string>
00017 #include <sstream>
00018 #include <fstream>
00019 #include <regex>
00020 #include <thread>
00021 #include <utility>
00022 #include <chrono>
00023 #include <thread>
00024
00025 #include <dirent.h>
00026 #include <fcntl.h>
00027 #include <unistd.h>
00028 #include <limits.h>
00029 #include <errno.h>
00030 #include <sys/stat.h>
00031 #include <sys/mman.h>
00032 #include <sys/ioctl.h>
00033 #include <sys/sysmacros.h>
00034 #include <linux/usb/video.h>
00035 #include <linux/uvcvideo.h>
00036 #include <linux/videodev2.h>
00037
00038 #pragma GCC diagnostic ignored "-Wpedantic"
00039 #include <libusb.h>
00040 #pragma GCC diagnostic pop
00041
00042 #pragma GCC diagnostic ignored "-Woverflow"
00043
00044 namespace rsimpl
00045 {
00046 namespace uvc
00047 {
00048 static void throw_error(const char * s)
00049 {
00050 std::ostringstream ss;
00051 ss << s << " error " << errno << ", " << strerror(errno);
00052 throw std::runtime_error(ss.str());
00053 }
00054
00055 static void warn_error(const char * s)
00056 {
00057 LOG_ERROR(s << " error " << errno << ", " << strerror(errno));
00058 }
00059
00060 static int xioctl(int fh, int request, void *arg)
00061 {
00062 int r;
00063 do {
00064 r = ioctl(fh, request, arg);
00065 } while (r < 0 && errno == EINTR);
00066 return r;
00067 }
00068
00069 struct buffer { void * start; size_t length; };
00070
00071 struct context
00072 {
00073 libusb_context * usb_context;
00074
00075 context()
00076 {
00077 int status = libusb_init(&usb_context);
00078 if(status < 0) throw std::runtime_error(to_string() << "libusb_init(...) returned " << libusb_error_name(status));
00079 }
00080 ~context()
00081 {
00082 libusb_exit(usb_context);
00083 }
00084 };
00085
00086 struct subdevice
00087 {
00088 std::string dev_name;
00089 int busnum, devnum, parent_devnum;
00090 int vid, pid, mi;
00091 int fd;
00092 std::vector<buffer> buffers;
00093
00094 int width, height, format, fps;
00095 video_channel_callback callback = nullptr;
00096 data_channel_callback channel_data_callback = nullptr;
00097 bool is_capturing;
00098 bool is_metastream;
00099
00100 subdevice(const std::string & name) : dev_name("/dev/" + name), vid(), pid(), fd(), width(), height(), format(), callback(nullptr), channel_data_callback(nullptr), is_capturing(), is_metastream()
00101 {
00102 struct stat st;
00103 if(stat(dev_name.c_str(), &st) < 0)
00104 {
00105 std::ostringstream ss; ss << "Cannot identify '" << dev_name << "': " << errno << ", " << strerror(errno);
00106 throw std::runtime_error(ss.str());
00107 }
00108 if(!S_ISCHR(st.st_mode)) throw std::runtime_error(dev_name + " is no device");
00109
00110
00111 std::ostringstream ss; ss << "/sys/dev/char/" << major(st.st_rdev) << ":" << minor(st.st_rdev) << "/device/";
00112 auto path = ss.str();
00113 bool good = false;
00114 for(int i=0; i<=3; ++i)
00115 {
00116 if(std::ifstream(path + "busnum") >> busnum)
00117 {
00118 if(std::ifstream(path + "devnum") >> devnum)
00119 {
00120 if(std::ifstream(path + "../devnum") >> parent_devnum)
00121 {
00122 good = true;
00123 break;
00124 }
00125 }
00126 }
00127 path += "../";
00128 }
00129 if(!good) throw std::runtime_error("Failed to read busnum/devnum");
00130
00131 std::string modalias;
00132 if(!(std::ifstream("/sys/class/video4linux/" + name + "/device/modalias") >> modalias))
00133 throw std::runtime_error("Failed to read modalias");
00134 if(modalias.size() < 14 || modalias.substr(0,5) != "usb:v" || modalias[9] != 'p')
00135 throw std::runtime_error("Not a usb format modalias");
00136 if(!(std::istringstream(modalias.substr(5,4)) >> std::hex >> vid))
00137 throw std::runtime_error("Failed to read vendor ID");
00138 if(!(std::istringstream(modalias.substr(10,4)) >> std::hex >> pid))
00139 throw std::runtime_error("Failed to read product ID");
00140 if(!(std::ifstream("/sys/class/video4linux/" + name + "/device/bInterfaceNumber") >> std::hex >> mi))
00141 throw std::runtime_error("Failed to read interface number");
00142
00143 fd = open(dev_name.c_str(), O_RDWR | O_NONBLOCK, 0);
00144 if(fd < 0)
00145 {
00146 std::ostringstream ss; ss << "Cannot open '" << dev_name << "': " << errno << ", " << strerror(errno);
00147 throw std::runtime_error(ss.str());
00148 }
00149
00150 v4l2_capability cap = {};
00151 if(xioctl(fd, VIDIOC_QUERYCAP, &cap) < 0)
00152 {
00153 if(errno == EINVAL) throw std::runtime_error(dev_name + " is no V4L2 device");
00154 else throw_error("VIDIOC_QUERYCAP");
00155 }
00156 if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) throw std::runtime_error(dev_name + " is no video capture device");
00157 if(!(cap.capabilities & V4L2_CAP_STREAMING)) throw std::runtime_error(dev_name + " does not support streaming I/O");
00158 if((cap.device_caps & V4L2_CAP_META_CAPTURE)){
00159 is_metastream=true;
00160 }
00161
00162
00163 v4l2_cropcap cropcap = {};
00164 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00165 if(xioctl(fd, VIDIOC_CROPCAP, &cropcap) == 0)
00166 {
00167 v4l2_crop crop = {};
00168 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00169 crop.c = cropcap.defrect;
00170 if(xioctl(fd, VIDIOC_S_CROP, &crop) < 0)
00171 {
00172 switch (errno)
00173 {
00174 case EINVAL: break;
00175 default: break;
00176 }
00177 }
00178 } else {}
00179 }
00180
00181 ~subdevice()
00182 {
00183 stop_capture();
00184 if(close(fd) < 0) warn_error("close");
00185 }
00186
00187 int get_vid() const { return vid; }
00188 int get_pid() const { return pid; }
00189 int get_mi() const { return mi; }
00190
00191 void get_control(const extension_unit & xu, uint8_t control, void * data, size_t size)
00192 {
00193 uvc_xu_control_query q = {static_cast<uint8_t>(xu.unit), control, UVC_GET_CUR, static_cast<uint16_t>(size), reinterpret_cast<uint8_t *>(data)};
00194 if(xioctl(fd, UVCIOC_CTRL_QUERY, &q) < 0) throw_error("UVCIOC_CTRL_QUERY:UVC_GET_CUR");
00195 }
00196
00197 void set_control(const extension_unit & xu, uint8_t control, void * data, size_t size)
00198 {
00199 uvc_xu_control_query q = {static_cast<uint8_t>(xu.unit), control, UVC_SET_CUR, static_cast<uint16_t>(size), reinterpret_cast<uint8_t *>(data)};
00200 if(xioctl(fd, UVCIOC_CTRL_QUERY, &q) < 0) throw_error("UVCIOC_CTRL_QUERY:UVC_SET_CUR");
00201 }
00202
00203 void set_format(int width, int height, int fourcc, int fps, video_channel_callback callback)
00204 {
00205 this->width = width;
00206 this->height = height;
00207 this->format = fourcc;
00208 this->fps = fps;
00209 this->callback = callback;
00210 }
00211
00212 void set_data_channel_cfg(data_channel_callback callback)
00213 {
00214 this->channel_data_callback = callback;
00215 }
00216
00217 void start_capture()
00218 {
00219 if(!is_capturing)
00220 {
00221 v4l2_format fmt = {};
00222 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00223 fmt.fmt.pix.width = width;
00224 fmt.fmt.pix.height = height;
00225 fmt.fmt.pix.pixelformat = format;
00226 fmt.fmt.pix.field = V4L2_FIELD_NONE;
00227 if(xioctl(fd, VIDIOC_S_FMT, &fmt) < 0) throw_error("VIDIOC_S_FMT");
00228
00229 v4l2_streamparm parm = {};
00230 parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00231 if(xioctl(fd, VIDIOC_G_PARM, &parm) < 0) throw_error("VIDIOC_G_PARM");
00232 parm.parm.capture.timeperframe.numerator = 1;
00233 parm.parm.capture.timeperframe.denominator = fps;
00234 if(xioctl(fd, VIDIOC_S_PARM, &parm) < 0) throw_error("VIDIOC_S_PARM");
00235
00236
00237 v4l2_requestbuffers req = {};
00238 req.count = 4;
00239 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00240 req.memory = V4L2_MEMORY_MMAP;
00241 if(xioctl(fd, VIDIOC_REQBUFS, &req) < 0)
00242 {
00243 if(errno == EINVAL) throw std::runtime_error(dev_name + " does not support memory mapping");
00244 else throw_error("VIDIOC_REQBUFS");
00245 }
00246 if(req.count < 2)
00247 {
00248 throw std::runtime_error("Insufficient buffer memory on " + dev_name);
00249 }
00250
00251 buffers.resize(req.count);
00252 for(size_t i = 0; i < buffers.size(); ++i)
00253 {
00254 v4l2_buffer buf = {};
00255 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00256 buf.memory = V4L2_MEMORY_MMAP;
00257 buf.index = i;
00258 if(xioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) throw_error("VIDIOC_QUERYBUF");
00259
00260 buffers[i].length = buf.length;
00261 buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
00262 if(buffers[i].start == MAP_FAILED) throw_error("mmap");
00263 }
00264
00265
00266 for(size_t i = 0; i < buffers.size(); ++i)
00267 {
00268 v4l2_buffer buf = {};
00269 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00270 buf.memory = V4L2_MEMORY_MMAP;
00271 buf.index = i;
00272 if(xioctl(fd, VIDIOC_QBUF, &buf) < 0) throw_error("VIDIOC_QBUF");
00273 }
00274
00275 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00276 for(int i=0; i<10; ++i)
00277 {
00278 if(xioctl(fd, VIDIOC_STREAMON, &type) < 0)
00279 {
00280 std::this_thread::sleep_for(std::chrono::milliseconds(100));
00281 }
00282 }
00283 if(xioctl(fd, VIDIOC_STREAMON, &type) < 0) throw_error("VIDIOC_STREAMON");
00284
00285 is_capturing = true;
00286 }
00287 }
00288
00289 void stop_capture()
00290 {
00291 if(is_capturing)
00292 {
00293
00294 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00295 if(xioctl(fd, VIDIOC_STREAMOFF, &type) < 0) warn_error("VIDIOC_STREAMOFF");
00296
00297 for(size_t i = 0; i < buffers.size(); i++)
00298 {
00299 if(munmap(buffers[i].start, buffers[i].length) < 0) warn_error("munmap");
00300 }
00301
00302
00303 struct v4l2_requestbuffers req = {};
00304 req.count = 0;
00305 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00306 req.memory = V4L2_MEMORY_MMAP;
00307 if(xioctl(fd, VIDIOC_REQBUFS, &req) < 0)
00308 {
00309 if(errno == EINVAL) LOG_ERROR(dev_name + " does not support memory mapping");
00310 else warn_error("VIDIOC_REQBUFS");
00311 }
00312
00313 callback = nullptr;
00314 is_capturing = false;
00315 }
00316 }
00317
00318 static void poll(const std::vector<subdevice *> & subdevices)
00319 {
00320 int max_fd = 0;
00321 fd_set fds;
00322 FD_ZERO(&fds);
00323 for(auto * sub : subdevices)
00324 {
00325 FD_SET(sub->fd, &fds);
00326 max_fd = std::max(max_fd, sub->fd);
00327 }
00328
00329 struct timeval tv = {0,10000};
00330 if(select(max_fd + 1, &fds, NULL, NULL, &tv) < 0)
00331 {
00332 if (errno == EINTR) return;
00333 throw_error("select");
00334 }
00335
00336 for(auto * sub : subdevices)
00337 {
00338 if(FD_ISSET(sub->fd, &fds))
00339 {
00340 v4l2_buffer buf = {};
00341 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00342 buf.memory = V4L2_MEMORY_MMAP;
00343 if(xioctl(sub->fd, VIDIOC_DQBUF, &buf) < 0)
00344 {
00345 if(errno == EAGAIN) return;
00346 throw_error("VIDIOC_DQBUF");
00347 }
00348
00349 sub->callback(sub->buffers[buf.index].start,
00350 [sub, buf]() mutable {
00351 if(xioctl(sub->fd, VIDIOC_QBUF, &buf) < 0) throw_error("VIDIOC_QBUF");
00352 });
00353 }
00354 }
00355 }
00356
00357 static void poll_interrupts(libusb_device_handle *handle, const std::vector<subdevice *> & subdevices, uint16_t timeout)
00358 {
00359 static const unsigned short interrupt_buf_size = 0x400;
00360 uint8_t buffer[interrupt_buf_size];
00361 int num_bytes = 0;
00362
00363
00364 int res = libusb_interrupt_transfer(handle, 0x84, buffer, interrupt_buf_size, &num_bytes, timeout);
00365 if (0 == res)
00366 {
00367
00368 for(auto & sub : subdevices)
00369 if (sub->channel_data_callback)
00370 sub->channel_data_callback(buffer, num_bytes);
00371 }
00372 else
00373 {
00374 switch (res)
00375 {
00376 case LIBUSB_ERROR_TIMEOUT :
00377 LOG_WARNING("interrupt e.p. timeout");
00378 break;
00379 default:
00380 throw std::runtime_error(to_string() << "USB Interrupt end-point error " << libusb_strerror((libusb_error)res));
00381 break;
00382 }
00383 }
00384 }
00385 };
00386
00387 struct device
00388 {
00389 const std::shared_ptr<context> parent;
00390 std::vector<std::unique_ptr<subdevice>> subdevices;
00391 std::thread thread;
00392 std::thread data_channel_thread;
00393 volatile bool stop;
00394 volatile bool data_stop;
00395
00396 libusb_device * usb_device;
00397 libusb_device_handle * usb_handle;
00398 std::vector<int> claimed_interfaces;
00399
00400 device(std::shared_ptr<context> parent) : parent(parent), stop(), data_stop(), usb_device(), usb_handle() {}
00401 ~device()
00402 {
00403 stop_streaming();
00404
00405 for(auto interface_number : claimed_interfaces)
00406 {
00407 int status = libusb_release_interface(usb_handle, interface_number);
00408 if(status < 0) LOG_ERROR("libusb_release_interface(...) returned " << libusb_error_name(status));
00409 }
00410
00411 if(usb_handle) libusb_close(usb_handle);
00412 if(usb_device) libusb_unref_device(usb_device);
00413 }
00414
00415 bool has_mi(int mi) const
00416 {
00417 for(auto & sub : subdevices)
00418 {
00419 if(sub->get_mi() == mi) return true;
00420 }
00421 return false;
00422 }
00423
00424 void start_streaming()
00425 {
00426 std::vector<subdevice *> subs;
00427
00428 for(auto & sub : subdevices)
00429 {
00430 if(sub->callback)
00431 {
00432 sub->start_capture();
00433 subs.push_back(sub.get());
00434 }
00435 }
00436
00437 thread = std::thread([this, subs]()
00438 {
00439 while(!stop) subdevice::poll(subs);
00440 });
00441 }
00442
00443 void stop_streaming()
00444 {
00445 if(thread.joinable())
00446 {
00447 stop = true;
00448 thread.join();
00449 stop = false;
00450
00451 for(auto & sub : subdevices) sub->stop_capture();
00452 }
00453 }
00454
00455 void start_data_acquisition()
00456 {
00457 std::vector<subdevice *> data_channel_subs;
00458 for (auto & sub : subdevices)
00459 {
00460 if (sub->channel_data_callback)
00461 {
00462 data_channel_subs.push_back(sub.get());
00463 }
00464 }
00465
00466
00467 if (claimed_interfaces.size())
00468 {
00469 data_channel_thread = std::thread([this, data_channel_subs]()
00470 {
00471
00472 while (!data_stop)
00473 {
00474 subdevice::poll_interrupts(this->usb_handle, data_channel_subs, 100);
00475 }
00476 });
00477 }
00478 }
00479
00480 void stop_data_acquisition()
00481 {
00482 if (data_channel_thread.joinable())
00483 {
00484 data_stop = true;
00485 data_channel_thread.join();
00486 data_stop = false;
00487 }
00488 }
00489 };
00490
00492
00494
00495 int get_vendor_id(const device & device) { return device.subdevices[0]->get_vid(); }
00496 int get_product_id(const device & device) { return device.subdevices[0]->get_pid(); }
00497
00498 std::string get_usb_port_id(const device & device)
00499 {
00500 std::string usb_bus = std::to_string(libusb_get_bus_number(device.usb_device));
00501
00502
00503 const int max_usb_depth = 8;
00504 uint8_t usb_ports[max_usb_depth];
00505 std::stringstream port_path;
00506 int port_count = libusb_get_port_numbers(device.usb_device, usb_ports, max_usb_depth);
00507
00508 for (size_t i = 0; i < port_count; ++i)
00509 {
00510 port_path << "-" << std::to_string(usb_ports[i]);
00511 }
00512
00513 return usb_bus + port_path.str();
00514 }
00515
00516 void get_control(const device & device, const extension_unit & xu, uint8_t ctrl, void * data, int len)
00517 {
00518 device.subdevices[xu.subdevice]->get_control(xu, ctrl, data, len);
00519 }
00520 void set_control(device & device, const extension_unit & xu, uint8_t ctrl, void * data, int len)
00521 {
00522 device.subdevices[xu.subdevice]->set_control(xu, ctrl, data, len);
00523 }
00524
00525 void claim_interface(device & device, const guid & , int interface_number)
00526 {
00527 if(!device.usb_handle)
00528 {
00529 int status = libusb_open(device.usb_device, &device.usb_handle);
00530 if(status < 0) throw std::runtime_error(to_string() << "libusb_open(...) returned " << libusb_error_name(status));
00531 }
00532
00533 int status = libusb_claim_interface(device.usb_handle, interface_number);
00534 if(status < 0) throw std::runtime_error(to_string() << "libusb_claim_interface(...) returned " << libusb_error_name(status));
00535 device.claimed_interfaces.push_back(interface_number);
00536 }
00537 void claim_aux_interface(device & device, const guid & interface_guid, int interface_number)
00538 {
00539 claim_interface(device, interface_guid, interface_number);
00540 }
00541
00542 void bulk_transfer(device & device, unsigned char endpoint, void * data, int length, int *actual_length, unsigned int timeout)
00543 {
00544 if(!device.usb_handle) throw std::logic_error("called uvc::bulk_transfer before uvc::claim_interface");
00545 int status = libusb_bulk_transfer(device.usb_handle, endpoint, (unsigned char *)data, length, actual_length, timeout);
00546 if(status < 0) throw std::runtime_error(to_string() << "libusb_bulk_transfer(...) returned " << libusb_error_name(status));
00547 }
00548
00549 void interrupt_transfer(device & device, unsigned char endpoint, void * data, int length, int *actual_length, unsigned int timeout)
00550 {
00551 if(!device.usb_handle) throw std::logic_error("called uvc::interrupt_transfer before uvc::claim_interface");
00552 int status = libusb_interrupt_transfer(device.usb_handle, endpoint, (unsigned char *)data, length, actual_length, timeout);
00553 if(status < 0) throw std::runtime_error(to_string() << "libusb_interrupt_transfer(...) returned " << libusb_error_name(status));
00554 }
00555
00556 void set_subdevice_mode(device & device, int subdevice_index, int width, int height, uint32_t fourcc, int fps, video_channel_callback callback)
00557 {
00558 device.subdevices[subdevice_index]->set_format(width, height, (const big_endian<int> &)fourcc, fps, callback);
00559 }
00560
00561 void set_subdevice_data_channel_handler(device & device, int subdevice_index, data_channel_callback callback)
00562 {
00563 device.subdevices[subdevice_index]->set_data_channel_cfg(callback);
00564 }
00565
00566 void start_streaming(device & device, int )
00567 {
00568 device.start_streaming();
00569 }
00570
00571 void stop_streaming(device & device)
00572 {
00573 device.stop_streaming();
00574 }
00575
00576 void start_data_acquisition(device & device)
00577 {
00578 device.start_data_acquisition();
00579 }
00580
00581 void stop_data_acquisition(device & device)
00582 {
00583 device.stop_data_acquisition();
00584 }
00585
00586 static uint32_t get_cid(rs_option option)
00587 {
00588 switch(option)
00589 {
00590 case RS_OPTION_COLOR_BACKLIGHT_COMPENSATION: return V4L2_CID_BACKLIGHT_COMPENSATION;
00591 case RS_OPTION_COLOR_BRIGHTNESS: return V4L2_CID_BRIGHTNESS;
00592 case RS_OPTION_COLOR_CONTRAST: return V4L2_CID_CONTRAST;
00593 case RS_OPTION_COLOR_EXPOSURE: return V4L2_CID_EXPOSURE_ABSOLUTE;
00594 case RS_OPTION_COLOR_GAIN: return V4L2_CID_GAIN;
00595 case RS_OPTION_COLOR_GAMMA: return V4L2_CID_GAMMA;
00596 case RS_OPTION_COLOR_HUE: return V4L2_CID_HUE;
00597 case RS_OPTION_COLOR_SATURATION: return V4L2_CID_SATURATION;
00598 case RS_OPTION_COLOR_SHARPNESS: return V4L2_CID_SHARPNESS;
00599 case RS_OPTION_COLOR_WHITE_BALANCE: return V4L2_CID_WHITE_BALANCE_TEMPERATURE;
00600 case RS_OPTION_COLOR_ENABLE_AUTO_EXPOSURE: return V4L2_CID_EXPOSURE_AUTO;
00601 case RS_OPTION_COLOR_ENABLE_AUTO_WHITE_BALANCE: return V4L2_CID_AUTO_WHITE_BALANCE;
00602 case RS_OPTION_FISHEYE_GAIN: return V4L2_CID_GAIN;
00603 default: throw std::runtime_error(to_string() << "no v4l2 cid for option " << option);
00604 }
00605 }
00606
00607 void set_pu_control(device & device, int subdevice, rs_option option, int value)
00608 {
00609 struct v4l2_control control = {get_cid(option), value};
00610 if (RS_OPTION_COLOR_ENABLE_AUTO_EXPOSURE==option) { control.value = value ? V4L2_EXPOSURE_APERTURE_PRIORITY : V4L2_EXPOSURE_MANUAL; }
00611 if (xioctl(device.subdevices[subdevice]->fd, VIDIOC_S_CTRL, &control) < 0) throw_error("VIDIOC_S_CTRL");
00612 }
00613
00614 int get_pu_control(const device & device, int subdevice, rs_option option)
00615 {
00616 struct v4l2_control control = {get_cid(option), 0};
00617 if (xioctl(device.subdevices[subdevice]->fd, VIDIOC_G_CTRL, &control) < 0) throw_error("VIDIOC_G_CTRL");
00618 if (RS_OPTION_COLOR_ENABLE_AUTO_EXPOSURE==option) { control.value = (V4L2_EXPOSURE_MANUAL==control.value) ? 0 : 1; }
00619 return control.value;
00620 }
00621
00622 void get_pu_control_range(const device & device, int subdevice, rs_option option, int * min, int * max, int * step, int * def)
00623 {
00624
00625 if(option >= RS_OPTION_COLOR_ENABLE_AUTO_EXPOSURE && option <= RS_OPTION_COLOR_ENABLE_AUTO_WHITE_BALANCE)
00626 {
00627 if(min) *min = 0;
00628 if(max) *max = 1;
00629 if(step) *step = 1;
00630 if(def) *def = 1;
00631 return;
00632 }
00633
00634 struct v4l2_queryctrl query = {};
00635 query.id = get_cid(option);
00636 if (xioctl(device.subdevices[subdevice]->fd, VIDIOC_QUERYCTRL, &query) < 0)
00637 {
00638
00639
00640
00641 query.minimum = query.maximum = 0;
00642 }
00643 if(min) *min = query.minimum;
00644 if(max) *max = query.maximum;
00645 if(step) *step = query.step;
00646 if(def) *def = query.default_value;
00647 }
00648
00649 void get_extension_control_range(const device & device, const extension_unit & xu, char control, int * min, int * max, int * step, int * def)
00650 {
00651 __u16 size = 0;
00652 __u8 value = 0;
00653
00654
00655 __u8 * data = (__u8 *)&value;
00656 struct uvc_xu_control_query xquery;
00657 memset(&xquery, 0, sizeof(xquery));
00658 xquery.query = UVC_GET_LEN;
00659 xquery.size = 2;
00660
00661
00662 xquery.selector = control;
00663 xquery.unit = xu.unit;
00664 xquery.data = (__u8 *)&size;
00665
00666 if(-1 == ioctl(device.subdevices[xu.subdevice]->fd,UVCIOC_CTRL_QUERY,&xquery)){
00667 throw std::runtime_error(to_string() << " ioctl failed on UVC_GET_LEN");
00668 }
00669
00670 xquery.query = UVC_GET_MIN;
00671 xquery.size = size;
00672 xquery.selector = control;
00673 xquery.unit = xu.unit;
00674 xquery.data = data;
00675 if(-1 == ioctl(device.subdevices[xu.subdevice]->fd,UVCIOC_CTRL_QUERY,&xquery)){
00676 throw std::runtime_error(to_string() << " ioctl failed on UVC_GET_MIN");
00677 }
00678 *min = value;
00679
00680 xquery.query = UVC_GET_MAX;
00681 xquery.size = size;
00682 xquery.selector = control;
00683 xquery.unit = xu.unit;
00684 xquery.data = data;
00685 if(-1 == ioctl(device.subdevices[xu.subdevice]->fd,UVCIOC_CTRL_QUERY,&xquery)){
00686 throw std::runtime_error(to_string() << " ioctl failed on UVC_GET_MAX");
00687 }
00688 *max = value;
00689
00690 xquery.query = UVC_GET_DEF;
00691 xquery.size = size;
00692 xquery.selector = control;
00693 xquery.unit = xu.unit;
00694 xquery.data = data;
00695 if(-1 == ioctl(device.subdevices[xu.subdevice]->fd,UVCIOC_CTRL_QUERY,&xquery)){
00696 throw std::runtime_error(to_string() << " ioctl failed on UVC_GET_DEF");
00697 }
00698 *def = value;
00699
00700 xquery.query = UVC_GET_RES;
00701 xquery.size = size;
00702 xquery.selector = control;
00703 xquery.unit = xu.unit;
00704 xquery.data = data;
00705 if(-1 == ioctl(device.subdevices[xu.subdevice]->fd,UVCIOC_CTRL_QUERY,&xquery)){
00706 throw std::runtime_error(to_string() << " ioctl failed on UVC_GET_CUR");
00707 }
00708 *step = value;
00709
00710 }
00712
00714
00715 std::shared_ptr<context> create_context()
00716 {
00717 return std::make_shared<context>();
00718 }
00719
00720 bool is_device_connected(device & device, int vid, int pid)
00721 {
00722 for (auto& sub : device.subdevices)
00723 {
00724 if (sub->vid == vid && sub->pid == pid)
00725 return true;
00726 }
00727
00728 return false;
00729 }
00730
00731 std::vector<std::shared_ptr<device>> query_devices(std::shared_ptr<context> context)
00732 {
00733
00734 std::vector<std::unique_ptr<subdevice>> subdevices;
00735 DIR * dir = opendir("/sys/class/video4linux");
00736 if(!dir) throw std::runtime_error("Cannot access /sys/class/video4linux");
00737 while (dirent * entry = readdir(dir))
00738 {
00739 std::string name = entry->d_name;
00740 if(name == "." || name == "..") continue;
00741
00742
00743 std::string path = "/sys/class/video4linux/" + name;
00744 char buff[PATH_MAX];
00745 ssize_t len = ::readlink(path.c_str(), buff, sizeof(buff)-1);
00746 if (len != -1)
00747 {
00748 buff[len] = '\0';
00749 std::string real_path = std::string(buff);
00750 if (real_path.find("virtual") != std::string::npos)
00751 continue;
00752 }
00753
00754 try
00755 {
00756 std::unique_ptr<subdevice> sub(new subdevice(name));
00757 subdevices.push_back(move(sub));
00758 }
00759 catch(const std::exception & e)
00760 {
00761 LOG_INFO("Not a USB video device: " << e.what());
00762 }
00763 }
00764 closedir(dir);
00765
00766
00767
00768
00769
00770 std::vector<std::shared_ptr<device>> devices;
00771 for(auto & sub : subdevices)
00772 {
00773 bool is_new_device = true;
00774 for(auto & dev : devices)
00775 {
00776 if(sub->busnum == dev->subdevices[0]->busnum && sub->devnum == dev->subdevices[0]->devnum)
00777 {
00778 if (sub->is_metastream)
00779 continue;
00780 dev->subdevices.push_back(move(sub));
00781 is_new_device = false;
00782 break;
00783 }
00784 }
00785 if(is_new_device)
00786 {
00787 if (sub->vid == VID_INTEL_CAMERA && sub->pid == ZR300_FISHEYE_PID)
00788 continue;
00789 if (sub->is_metastream)
00790 continue;
00791 devices.push_back(std::make_shared<device>(context));
00792 devices.back()->subdevices.push_back(move(sub));
00793 }
00794 }
00795
00796
00797 for(auto & dev : devices)
00798 {
00799 std::sort(begin(dev->subdevices), end(dev->subdevices), [](const std::unique_ptr<subdevice> & a, const std::unique_ptr<subdevice> & b)
00800 {
00801 return a->mi < b->mi;
00802 });
00803 }
00804
00805
00806
00807 for(auto & sub : subdevices)
00808 {
00809 if (!sub)
00810 continue;
00811
00812 for(auto & dev : devices)
00813 {
00814 if (sub->is_metastream)
00815 continue;
00816 if (dev->subdevices[0]->vid == VID_INTEL_CAMERA && dev->subdevices[0]->pid == ZR300_CX3_PID &&
00817 sub->vid == VID_INTEL_CAMERA && sub->pid == ZR300_FISHEYE_PID && dev->subdevices[0]->parent_devnum == sub->parent_devnum)
00818 {
00819 dev->subdevices.push_back(move(sub));
00820 break;
00821 }
00822 }
00823 }
00824
00825
00826
00827 libusb_device ** list;
00828 int status = libusb_get_device_list(context->usb_context, &list);
00829 if(status < 0) throw std::runtime_error(to_string() << "libusb_get_device_list(...) returned " << libusb_error_name(status));
00830 for(int i=0; list[i]; ++i)
00831 {
00832 libusb_device * usb_device = list[i];
00833 int busnum = libusb_get_bus_number(usb_device);
00834 int devnum = libusb_get_device_address(usb_device);
00835
00836
00837 for(auto & dev : devices)
00838 {
00839 if (dev->subdevices.size() >=4)
00840 {
00841 auto parent_device = libusb_get_parent(usb_device);
00842 if (parent_device)
00843 {
00844 int parent_devnum = libusb_get_device_address(libusb_get_parent(usb_device));
00845
00846
00847 bool bFishEyeDevice = ((busnum == dev->subdevices[3]->busnum) && (parent_devnum == dev->subdevices[3]->parent_devnum));
00848 if(bFishEyeDevice && !dev->usb_device)
00849 {
00850 dev->usb_device = usb_device;
00851 libusb_ref_device(usb_device);
00852 break;
00853 }
00854 }
00855 }
00856
00857 if(busnum == dev->subdevices[0]->busnum && devnum == dev->subdevices[0]->devnum)
00858 {
00859 if (!dev->usb_device)
00860 {
00861 dev->usb_device = usb_device;
00862 libusb_ref_device(usb_device);
00863 break;
00864 }
00865 }
00866 }
00867 }
00868 libusb_free_device_list(list, 1);
00869
00870 return devices;
00871 }
00872 }
00873 }
00874
00875 #endif