Program Listing for File utils.hpp
↰ Return to documentation for file (include/usb_cam/utils.hpp)
// Copyright 2014 Robert Bosch, LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of the Robert Bosch, LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef USB_CAM__UTILS_HPP_
#define USB_CAM__UTILS_HPP_
extern "C" {
#include <fcntl.h> // for open()
}
#include <sys/ioctl.h>
#include <sys/time.h>
#include <unistd.h> // for access
#include <cmath>
#include <ctime>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <map>
#include "linux/videodev2.h"
#include "usb_cam/constants.hpp"
namespace fs = std::filesystem;
namespace usb_cam
{
namespace utils
{
typedef enum
{
IO_METHOD_READ,
IO_METHOD_MMAP,
IO_METHOD_USERPTR,
IO_METHOD_UNKNOWN,
} io_method_t;
struct buffer
{
char * start;
size_t length;
};
inline time_t get_epoch_time_shift_us()
{
struct timeval epoch_time;
struct timespec monotonic_time;
gettimeofday(&epoch_time, NULL);
clock_gettime(CLOCK_MONOTONIC, &monotonic_time);
const int64_t uptime_us =
monotonic_time.tv_sec * 1000000 + static_cast<int64_t>(
std::round(monotonic_time.tv_nsec / 1000.0));
const int64_t epoch_us =
epoch_time.tv_sec * 1000000 + epoch_time.tv_usec;
return static_cast<time_t>(epoch_us - uptime_us);
}
inline timespec calc_img_timestamp(const timeval & buffer_time, const time_t & epoch_time_shift_us)
{
timespec img_timestamp;
int64_t buffer_time_us = (buffer_time.tv_sec * 1000000) + buffer_time.tv_usec;
buffer_time_us += epoch_time_shift_us;
img_timestamp.tv_sec = (buffer_time_us / 1000000);
img_timestamp.tv_nsec = (buffer_time_us % 1000000) * 1000;
return img_timestamp;
}
inline int xioctl(int fd, uint64_t request, void * arg)
{
int r = 0;
do {
r = ioctl(fd, request, arg);
continue;
} while (-1 == r && EINTR == errno);
return r;
}
inline io_method_t io_method_from_string(const std::string & str)
{
if (str == "mmap") {
return io_method_t::IO_METHOD_MMAP;
} else if (str == "read") {
return io_method_t::IO_METHOD_READ;
} else if (str == "userptr") {
return io_method_t::IO_METHOD_USERPTR;
} else {
return io_method_t::IO_METHOD_UNKNOWN;
}
}
inline std::map<std::string, v4l2_capability> available_devices()
{
// Initialize vector of device strings to fill in
std::map<std::string, v4l2_capability> v4l2_devices;
// Get a list of all v4l2 devices from /sys/class/video4linux
const std::string v4l2_symlinks_dir = "/sys/class/video4linux/";
for (const auto & device_symlink : fs::directory_iterator(v4l2_symlinks_dir)) {
if (fs::is_symlink(device_symlink)) {
// device_str is the full path to the device in /sys/devices/*
std::string device_str = fs::canonical(
v4l2_symlinks_dir + fs::read_symlink(
device_symlink).generic_string());
// get the proper device name (e.g. /dev/*)
std::ifstream uevent_file(device_str + "/uevent");
std::string line;
std::string device_name;
while (std::getline(uevent_file, line)) {
auto dev_name_index = line.find("DEVNAME=");
if (dev_name_index != std::string::npos) {
device_name = "/dev/" + line.substr(dev_name_index + 8, line.size());
break;
}
}
int fd;
// Try and open device to test access
if ((fd = open(device_name.c_str(), O_RDONLY)) == -1) {
std::cerr << "Cannot open device: `" << device_name << "`, ";
std::cerr << "double-check read / write permissions for device" << std::endl;
} else {
struct v4l2_capability device_capabilities = {};
if (xioctl(fd, VIDIOC_QUERYCAP, &device_capabilities) == -1) {
std::cerr << "Could not retrieve device capabilities: `" << device_name;
std::cerr << "`" << std::endl;
} else {
v4l2_devices[device_name] = device_capabilities;
}
}
} else {
// device doesn't exist, continue
continue;
}
}
return v4l2_devices;
}
} // namespace utils
} // namespace usb_cam
#endif // USB_CAM__UTILS_HPP_