mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-03 03:01:44 +00:00
Refactor UsbCameraProperty.
This commit is contained in:
@@ -88,22 +88,6 @@ static __u32 FromPixelFormat(VideoMode::PixelFormat pixelFormat) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes non-alphanumeric characters and replaces spaces with underscores.
|
|
||||||
// e.g. "Zoom, Absolute" -> "zoom_absolute", "Pan (Absolute)" -> "pan_absolute"
|
|
||||||
static llvm::StringRef NormalizeName(llvm::StringRef name,
|
|
||||||
llvm::SmallVectorImpl<char>& buf) {
|
|
||||||
bool newWord = false;
|
|
||||||
for (auto ch : name) {
|
|
||||||
if (std::isalnum(ch)) {
|
|
||||||
if (newWord) buf.push_back('_');
|
|
||||||
newWord = false;
|
|
||||||
buf.push_back(std::tolower(ch));
|
|
||||||
} else if (!buf.empty())
|
|
||||||
newWord = true;
|
|
||||||
}
|
|
||||||
return llvm::StringRef(buf.data(), buf.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsPercentageProperty(llvm::StringRef name) {
|
static bool IsPercentageProperty(llvm::StringRef name) {
|
||||||
if (name.startswith("raw_")) name = name.substr(4);
|
if (name.startswith("raw_")) name = name.substr(4);
|
||||||
return name == "brightness" || name == "contrast" || name == "saturation" ||
|
return name == "brightness" || name == "contrast" || name == "saturation" ||
|
||||||
@@ -111,117 +95,21 @@ static bool IsPercentageProperty(llvm::StringRef name) {
|
|||||||
name == "exposure_absolute";
|
name == "exposure_absolute";
|
||||||
}
|
}
|
||||||
|
|
||||||
int UsbCameraImpl::RawToPercentage(const PropertyData& rawProp, int rawValue) {
|
int UsbCameraImpl::RawToPercentage(const UsbCameraProperty& rawProp,
|
||||||
|
int rawValue) {
|
||||||
return 100.0 * (rawValue - rawProp.minimum) /
|
return 100.0 * (rawValue - rawProp.minimum) /
|
||||||
(rawProp.maximum - rawProp.minimum);
|
(rawProp.maximum - rawProp.minimum);
|
||||||
}
|
}
|
||||||
|
|
||||||
int UsbCameraImpl::PercentageToRaw(const PropertyData& rawProp,
|
int UsbCameraImpl::PercentageToRaw(const UsbCameraProperty& rawProp,
|
||||||
int percentValue) {
|
int percentValue) {
|
||||||
return rawProp.minimum +
|
return rawProp.minimum +
|
||||||
(rawProp.maximum - rawProp.minimum) * (percentValue / 100.0);
|
(rawProp.maximum - rawProp.minimum) * (percentValue / 100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VIDIOC_QUERY_EXT_CTRL
|
static std::unique_ptr<UsbCameraProperty> ExtCtrlIoctl(int fd, __u32* id) {
|
||||||
UsbCameraImpl::PropertyData::PropertyData(
|
|
||||||
const struct v4l2_query_ext_ctrl& ctrl)
|
|
||||||
: PropertyImpl(llvm::StringRef{}, CS_PROP_NONE, ctrl.step,
|
|
||||||
ctrl.default_value, 0),
|
|
||||||
id(ctrl.id & V4L2_CTRL_ID_MASK),
|
|
||||||
type(ctrl.type) {
|
|
||||||
hasMinimum = true;
|
|
||||||
minimum = ctrl.minimum;
|
|
||||||
hasMaximum = true;
|
|
||||||
maximum = ctrl.maximum;
|
|
||||||
|
|
||||||
// propKind
|
|
||||||
switch (ctrl.type) {
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER:
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER64:
|
|
||||||
propKind = CS_PROP_INTEGER;
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_BOOLEAN:
|
|
||||||
propKind = CS_PROP_BOOLEAN;
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
|
||||||
case V4L2_CTRL_TYPE_MENU:
|
|
||||||
propKind = CS_PROP_ENUM;
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_STRING:
|
|
||||||
propKind = CS_PROP_STRING;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return; // others unsupported
|
|
||||||
}
|
|
||||||
|
|
||||||
// name
|
|
||||||
std::size_t len = 0;
|
|
||||||
while (len < sizeof(ctrl.name) && ctrl.name[len] != '\0') ++len;
|
|
||||||
llvm::SmallString<64> name_buf;
|
|
||||||
name = NormalizeName(llvm::StringRef(ctrl.name, len), name_buf);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UsbCameraImpl::PropertyData::PropertyData(const struct v4l2_queryctrl& ctrl)
|
|
||||||
: PropertyImpl(llvm::StringRef{}, CS_PROP_NONE, ctrl.step,
|
|
||||||
ctrl.default_value, 0),
|
|
||||||
id(ctrl.id & V4L2_CTRL_ID_MASK),
|
|
||||||
type(ctrl.type) {
|
|
||||||
hasMinimum = true;
|
|
||||||
minimum = ctrl.minimum;
|
|
||||||
hasMaximum = true;
|
|
||||||
maximum = ctrl.maximum;
|
|
||||||
|
|
||||||
// propKind
|
|
||||||
switch (ctrl.type) {
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER:
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER64:
|
|
||||||
propKind = CS_PROP_INTEGER;
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_BOOLEAN:
|
|
||||||
propKind = CS_PROP_BOOLEAN;
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
|
||||||
case V4L2_CTRL_TYPE_MENU:
|
|
||||||
propKind = CS_PROP_ENUM;
|
|
||||||
break;
|
|
||||||
case V4L2_CTRL_TYPE_STRING:
|
|
||||||
propKind = CS_PROP_STRING;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return; // others unsupported
|
|
||||||
}
|
|
||||||
|
|
||||||
// name
|
|
||||||
std::size_t len = 0;
|
|
||||||
while (len < sizeof(ctrl.name) && ctrl.name[len] != '\0') ++len;
|
|
||||||
llvm::SmallString<64> name_buf;
|
|
||||||
name = NormalizeName(
|
|
||||||
llvm::StringRef(reinterpret_cast<const char*>(ctrl.name), len), name_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int CheckedIoctl(int fd, unsigned long req, void* data,
|
|
||||||
const char* name, const char* file, int line,
|
|
||||||
bool quiet) {
|
|
||||||
int retval = ioctl(fd, req, data);
|
|
||||||
if (!quiet && retval < 0) {
|
|
||||||
llvm::SmallString<64> localfile{file};
|
|
||||||
localfile.push_back('\0');
|
|
||||||
ERROR("ioctl " << name << " failed at " << basename(localfile.data()) << ":"
|
|
||||||
<< line << ": " << std::strerror(errno));
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DoIoctl(fd, req, data) \
|
|
||||||
CheckedIoctl(fd, req, data, #req, __FILE__, __LINE__, false)
|
|
||||||
#define TryIoctl(fd, req, data) \
|
|
||||||
CheckedIoctl(fd, req, data, #req, __FILE__, __LINE__, true)
|
|
||||||
|
|
||||||
static std::unique_ptr<UsbCameraImpl::PropertyData> ExtCtrlIoctl(int fd,
|
|
||||||
__u32* id) {
|
|
||||||
int rc;
|
int rc;
|
||||||
std::unique_ptr<UsbCameraImpl::PropertyData> prop;
|
std::unique_ptr<UsbCameraProperty> prop;
|
||||||
#ifdef VIDIOC_QUERY_EXT_CTRL
|
#ifdef VIDIOC_QUERY_EXT_CTRL
|
||||||
v4l2_query_ext_ctrl qc_ext;
|
v4l2_query_ext_ctrl qc_ext;
|
||||||
std::memset(&qc_ext, 0, sizeof(qc_ext));
|
std::memset(&qc_ext, 0, sizeof(qc_ext));
|
||||||
@@ -231,7 +119,7 @@ static std::unique_ptr<UsbCameraImpl::PropertyData> ExtCtrlIoctl(int fd,
|
|||||||
*id = qc_ext.id; // copy back
|
*id = qc_ext.id; // copy back
|
||||||
// We don't support array types
|
// We don't support array types
|
||||||
if (qc_ext.elems > 1 || qc_ext.nr_of_dims > 0) return nullptr;
|
if (qc_ext.elems > 1 || qc_ext.nr_of_dims > 0) return nullptr;
|
||||||
prop = llvm::make_unique<UsbCameraImpl::PropertyData>(qc_ext);
|
prop = llvm::make_unique<UsbCameraProperty>(qc_ext);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
@@ -242,7 +130,7 @@ static std::unique_ptr<UsbCameraImpl::PropertyData> ExtCtrlIoctl(int fd,
|
|||||||
rc = TryIoctl(fd, VIDIOC_QUERYCTRL, &qc);
|
rc = TryIoctl(fd, VIDIOC_QUERYCTRL, &qc);
|
||||||
*id = qc.id; // copy back
|
*id = qc.id; // copy back
|
||||||
if (rc != 0) return nullptr;
|
if (rc != 0) return nullptr;
|
||||||
prop = llvm::make_unique<UsbCameraImpl::PropertyData>(qc);
|
prop = llvm::make_unique<UsbCameraProperty>(qc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache enum property choices
|
// Cache enum property choices
|
||||||
@@ -261,100 +149,6 @@ static std::unique_ptr<UsbCameraImpl::PropertyData> ExtCtrlIoctl(int fd,
|
|||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GetIntCtrlIoctl(int fd, unsigned id, int type, int64_t* value) {
|
|
||||||
unsigned ctrl_class = V4L2_CTRL_ID2CLASS(id);
|
|
||||||
if (type == V4L2_CTRL_TYPE_INTEGER64 || V4L2_CTRL_DRIVER_PRIV(id) ||
|
|
||||||
(ctrl_class != V4L2_CTRL_CLASS_USER &&
|
|
||||||
ctrl_class != V4L2_CID_PRIVATE_BASE)) {
|
|
||||||
// Use extended control
|
|
||||||
struct v4l2_ext_control ctrl;
|
|
||||||
struct v4l2_ext_controls ctrls;
|
|
||||||
std::memset(&ctrl, 0, sizeof(ctrl));
|
|
||||||
std::memset(&ctrls, 0, sizeof(ctrls));
|
|
||||||
ctrl.id = id;
|
|
||||||
ctrls.ctrl_class = ctrl_class;
|
|
||||||
ctrls.count = 1;
|
|
||||||
ctrls.controls = &ctrl;
|
|
||||||
int rc = DoIoctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls);
|
|
||||||
if (rc < 0) return rc;
|
|
||||||
*value = ctrl.value;
|
|
||||||
} else {
|
|
||||||
// Use normal control
|
|
||||||
struct v4l2_control ctrl;
|
|
||||||
std::memset(&ctrl, 0, sizeof(ctrl));
|
|
||||||
ctrl.id = id;
|
|
||||||
int rc = DoIoctl(fd, VIDIOC_G_CTRL, &ctrl);
|
|
||||||
if (rc < 0) return rc;
|
|
||||||
*value = ctrl.value;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int SetIntCtrlIoctl(int fd, unsigned id, int type, int64_t value) {
|
|
||||||
unsigned ctrl_class = V4L2_CTRL_ID2CLASS(id);
|
|
||||||
if (type == V4L2_CTRL_TYPE_INTEGER64 || V4L2_CTRL_DRIVER_PRIV(id) ||
|
|
||||||
(ctrl_class != V4L2_CTRL_CLASS_USER &&
|
|
||||||
ctrl_class != V4L2_CID_PRIVATE_BASE)) {
|
|
||||||
// Use extended control
|
|
||||||
struct v4l2_ext_control ctrl;
|
|
||||||
struct v4l2_ext_controls ctrls;
|
|
||||||
std::memset(&ctrl, 0, sizeof(ctrl));
|
|
||||||
std::memset(&ctrls, 0, sizeof(ctrls));
|
|
||||||
ctrl.id = id;
|
|
||||||
if (type == V4L2_CTRL_TYPE_INTEGER64)
|
|
||||||
ctrl.value64 = value;
|
|
||||||
else
|
|
||||||
ctrl.value = static_cast<__s32>(value);
|
|
||||||
ctrls.ctrl_class = ctrl_class;
|
|
||||||
ctrls.count = 1;
|
|
||||||
ctrls.controls = &ctrl;
|
|
||||||
return DoIoctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
|
|
||||||
} else {
|
|
||||||
// Use normal control
|
|
||||||
struct v4l2_control ctrl;
|
|
||||||
ctrl.id = id;
|
|
||||||
ctrl.value = static_cast<__s32>(value);
|
|
||||||
return DoIoctl(fd, VIDIOC_S_CTRL, &ctrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int GetStringCtrlIoctl(int fd, int id, int maximum,
|
|
||||||
std::string* value) {
|
|
||||||
struct v4l2_ext_control ctrl;
|
|
||||||
struct v4l2_ext_controls ctrls;
|
|
||||||
std::memset(&ctrl, 0, sizeof(ctrl));
|
|
||||||
std::memset(&ctrls, 0, sizeof(ctrls));
|
|
||||||
ctrl.id = id;
|
|
||||||
ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(id);
|
|
||||||
ctrls.count = 1;
|
|
||||||
ctrls.controls = &ctrl;
|
|
||||||
int rc = DoIoctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls);
|
|
||||||
if (rc < 0) {
|
|
||||||
value->clear();
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
value->assign(ctrl.string, std::strlen(ctrl.string));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int SetStringCtrlIoctl(int fd, int id, int maximum,
|
|
||||||
llvm::StringRef value) {
|
|
||||||
llvm::SmallString<64> str{value.substr(
|
|
||||||
0, std::min(value.size(), static_cast<std::size_t>(maximum)))};
|
|
||||||
|
|
||||||
struct v4l2_ext_control ctrl;
|
|
||||||
struct v4l2_ext_controls ctrls;
|
|
||||||
std::memset(&ctrl, 0, sizeof(ctrl));
|
|
||||||
std::memset(&ctrls, 0, sizeof(ctrls));
|
|
||||||
ctrl.id = id;
|
|
||||||
ctrl.size = str.size();
|
|
||||||
ctrl.string = const_cast<char*>(str.c_str());
|
|
||||||
ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(id);
|
|
||||||
ctrls.count = 1;
|
|
||||||
ctrls.controls = &ctrl;
|
|
||||||
return DoIoctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetDescriptionSysV4L(llvm::StringRef path, std::string* desc) {
|
static bool GetDescriptionSysV4L(llvm::StringRef path, std::string* desc) {
|
||||||
llvm::SmallString<64> ifpath{"/sys/class/video4linux/"};
|
llvm::SmallString<64> ifpath{"/sys/class/video4linux/"};
|
||||||
ifpath += path.substr(5);
|
ifpath += path.substr(5);
|
||||||
@@ -694,9 +488,9 @@ void UsbCameraImpl::DeviceConnect() {
|
|||||||
std::unique_lock<std::mutex> lock2(m_mutex);
|
std::unique_lock<std::mutex> lock2(m_mutex);
|
||||||
for (std::size_t i = 0; i < m_propertyData.size(); ++i) {
|
for (std::size_t i = 0; i < m_propertyData.size(); ++i) {
|
||||||
const auto prop =
|
const auto prop =
|
||||||
static_cast<const PropertyData*>(m_propertyData[i].get());
|
static_cast<const UsbCameraProperty*>(m_propertyData[i].get());
|
||||||
if (!prop || !prop->valueSet || prop->percentage) continue;
|
if (!prop || !prop->valueSet || prop->percentage) continue;
|
||||||
if (!DeviceSetProperty(lock2, *prop))
|
if (!prop->DeviceSet(lock2, m_fd))
|
||||||
SWARNING("failed to set property " << prop->name);
|
SWARNING("failed to set property " << prop->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1040,7 +834,8 @@ void UsbCameraImpl::DeviceCacheMode() {
|
|||||||
Notifier::GetInstance().NotifySource(*this, CS_SOURCE_VIDEOMODE_CHANGED);
|
Notifier::GetInstance().NotifySource(*this, CS_SOURCE_VIDEOMODE_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsbCameraImpl::DeviceCacheProperty(std::unique_ptr<PropertyData> rawProp) {
|
void UsbCameraImpl::DeviceCacheProperty(
|
||||||
|
std::unique_ptr<UsbCameraProperty> rawProp) {
|
||||||
// For percentage properties, we want to cache both the raw and the
|
// For percentage properties, we want to cache both the raw and the
|
||||||
// percentage versions. This function is always called with prop being
|
// percentage versions. This function is always called with prop being
|
||||||
// the raw property (as it's coming from the camera) so if required, we need
|
// the raw property (as it's coming from the camera) so if required, we need
|
||||||
@@ -1049,22 +844,25 @@ void UsbCameraImpl::DeviceCacheProperty(std::unique_ptr<PropertyData> rawProp) {
|
|||||||
// This is complicated by the fact that either the percentage version or the
|
// This is complicated by the fact that either the percentage version or the
|
||||||
// the raw version may have been set previously. If both were previously set,
|
// the raw version may have been set previously. If both were previously set,
|
||||||
// the raw version wins.
|
// the raw version wins.
|
||||||
std::unique_ptr<PropertyData> perProp;
|
std::unique_ptr<UsbCameraProperty> perProp;
|
||||||
if (IsPercentageProperty(rawProp->name)) {
|
if (IsPercentageProperty(rawProp->name)) {
|
||||||
perProp = llvm::make_unique<PropertyData>(rawProp->name, 0, *rawProp, 0, 0);
|
perProp =
|
||||||
|
llvm::make_unique<UsbCameraProperty>(rawProp->name, 0, *rawProp, 0, 0);
|
||||||
rawProp->name = "raw_" + perProp->name;
|
rawProp->name = "raw_" + perProp->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
int* rawIndex = &m_properties[rawProp->name];
|
int* rawIndex = &m_properties[rawProp->name];
|
||||||
bool newRaw = *rawIndex == 0;
|
bool newRaw = *rawIndex == 0;
|
||||||
PropertyData* oldRawProp =
|
UsbCameraProperty* oldRawProp =
|
||||||
newRaw ? nullptr : static_cast<PropertyData*>(GetProperty(*rawIndex));
|
newRaw ? nullptr
|
||||||
|
: static_cast<UsbCameraProperty*>(GetProperty(*rawIndex));
|
||||||
|
|
||||||
int* perIndex = perProp ? &m_properties[perProp->name] : nullptr;
|
int* perIndex = perProp ? &m_properties[perProp->name] : nullptr;
|
||||||
bool newPer = !perIndex || *perIndex == 0;
|
bool newPer = !perIndex || *perIndex == 0;
|
||||||
PropertyData* oldPerProp =
|
UsbCameraProperty* oldPerProp =
|
||||||
newPer ? nullptr : static_cast<PropertyData*>(GetProperty(*perIndex));
|
newPer ? nullptr
|
||||||
|
: static_cast<UsbCameraProperty*>(GetProperty(*perIndex));
|
||||||
|
|
||||||
if (oldRawProp && oldRawProp->valueSet) {
|
if (oldRawProp && oldRawProp->valueSet) {
|
||||||
// Merge existing raw setting and set percentage from it
|
// Merge existing raw setting and set percentage from it
|
||||||
@@ -1084,10 +882,8 @@ void UsbCameraImpl::DeviceCacheProperty(std::unique_ptr<PropertyData> rawProp) {
|
|||||||
rawProp->valueStr = perProp->valueStr; // copy
|
rawProp->valueStr = perProp->valueStr; // copy
|
||||||
} else {
|
} else {
|
||||||
// Read current raw value and set percentage from it
|
// Read current raw value and set percentage from it
|
||||||
lock.unlock();
|
if (!rawProp->DeviceGet(lock, m_fd))
|
||||||
if (!DeviceGetProperty(rawProp.get()))
|
|
||||||
SWARNING("failed to get property " << rawProp->name);
|
SWARNING("failed to get property " << rawProp->name);
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
if (perProp) {
|
if (perProp) {
|
||||||
perProp->SetValue(RawToPercentage(*rawProp, rawProp->value));
|
perProp->SetValue(RawToPercentage(*rawProp, rawProp->value));
|
||||||
@@ -1097,7 +893,7 @@ void UsbCameraImpl::DeviceCacheProperty(std::unique_ptr<PropertyData> rawProp) {
|
|||||||
|
|
||||||
// Set value on device if user-configured
|
// Set value on device if user-configured
|
||||||
if (rawProp->valueSet) {
|
if (rawProp->valueSet) {
|
||||||
if (!DeviceSetProperty(lock, *rawProp))
|
if (!rawProp->DeviceSet(lock, m_fd))
|
||||||
SWARNING("failed to set property " << rawProp->name);
|
SWARNING("failed to set property " << rawProp->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1164,7 +960,7 @@ void UsbCameraImpl::DeviceCacheProperties() {
|
|||||||
DeviceCacheProperty(std::move(prop));
|
DeviceCacheProperty(std::move(prop));
|
||||||
}
|
}
|
||||||
// ... and custom controls
|
// ... and custom controls
|
||||||
std::unique_ptr<PropertyData> prop;
|
std::unique_ptr<UsbCameraProperty> prop;
|
||||||
for (id = V4L2_CID_PRIVATE_BASE; (prop = ExtCtrlIoctl(fd, &id)); ++id)
|
for (id = V4L2_CID_PRIVATE_BASE; (prop = ExtCtrlIoctl(fd, &id)); ++id)
|
||||||
DeviceCacheProperty(std::move(prop));
|
DeviceCacheProperty(std::move(prop));
|
||||||
}
|
}
|
||||||
@@ -1218,77 +1014,11 @@ void UsbCameraImpl::DeviceCacheVideoModes() {
|
|||||||
Notifier::GetInstance().NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
|
Notifier::GetInstance().NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UsbCameraImpl::DeviceGetProperty(PropertyData* prop) {
|
|
||||||
int fd = m_fd.load();
|
|
||||||
if (fd < 0) return true;
|
|
||||||
int rv = 0;
|
|
||||||
|
|
||||||
switch (prop->propKind) {
|
|
||||||
case CS_PROP_BOOLEAN:
|
|
||||||
case CS_PROP_INTEGER:
|
|
||||||
case CS_PROP_ENUM:
|
|
||||||
{
|
|
||||||
int64_t value = 0;
|
|
||||||
rv = GetIntCtrlIoctl(fd, prop->id, prop->type, &value);
|
|
||||||
if (rv >= 0) prop->value = value;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CS_PROP_STRING:
|
|
||||||
rv = GetStringCtrlIoctl(fd, prop->id, prop->maximum, &prop->valueStr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UsbCameraImpl::DeviceSetProperty(std::unique_lock<std::mutex>& lock,
|
|
||||||
const PropertyData& prop) {
|
|
||||||
// Make a copy of the string as we're about to release the lock
|
|
||||||
llvm::SmallString<128> valueStr{prop.valueStr};
|
|
||||||
return DeviceSetProperty(lock, prop, prop.value, valueStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UsbCameraImpl::DeviceSetProperty(std::unique_lock<std::mutex>& lock,
|
|
||||||
const PropertyData& prop, int value,
|
|
||||||
llvm::StringRef valueStr) {
|
|
||||||
int fd = m_fd.load();
|
|
||||||
if (fd < 0) return true;
|
|
||||||
unsigned id = prop.id;
|
|
||||||
int rv = 0;
|
|
||||||
|
|
||||||
switch (prop.propKind) {
|
|
||||||
case CS_PROP_BOOLEAN:
|
|
||||||
case CS_PROP_INTEGER:
|
|
||||||
case CS_PROP_ENUM:
|
|
||||||
{
|
|
||||||
int type = prop.type;
|
|
||||||
lock.unlock();
|
|
||||||
rv = SetIntCtrlIoctl(fd, id, type, value);
|
|
||||||
lock.lock();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CS_PROP_STRING:
|
|
||||||
{
|
|
||||||
int maximum = prop.maximum;
|
|
||||||
lock.unlock();
|
|
||||||
rv = SetStringCtrlIoctl(fd, id, maximum, valueStr);
|
|
||||||
lock.lock();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CS_StatusValue UsbCameraImpl::DeviceCmdSetProperty(
|
CS_StatusValue UsbCameraImpl::DeviceCmdSetProperty(
|
||||||
std::unique_lock<std::mutex>& lock, int property, bool setString, int value,
|
std::unique_lock<std::mutex>& lock, int property, bool setString, int value,
|
||||||
llvm::StringRef valueStr) {
|
llvm::StringRef valueStr) {
|
||||||
// Look up
|
// Look up
|
||||||
auto prop = static_cast<PropertyData*>(GetProperty(property));
|
auto prop = static_cast<UsbCameraProperty*>(GetProperty(property));
|
||||||
if (!prop) return CS_INVALID_PROPERTY;
|
if (!prop) return CS_INVALID_PROPERTY;
|
||||||
|
|
||||||
// If setting before we get, guess initial type based on set
|
// If setting before we get, guess initial type based on set
|
||||||
@@ -1312,7 +1042,7 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetProperty(
|
|||||||
if (percentageProperty != 0) {
|
if (percentageProperty != 0) {
|
||||||
if (prop->percentage) {
|
if (prop->percentage) {
|
||||||
std::swap(percentageProperty, property);
|
std::swap(percentageProperty, property);
|
||||||
prop = static_cast<PropertyData*>(GetProperty(property));
|
prop = static_cast<UsbCameraProperty*>(GetProperty(property));
|
||||||
value = PercentageToRaw(*prop, percentageValue);
|
value = PercentageToRaw(*prop, percentageValue);
|
||||||
} else {
|
} else {
|
||||||
percentageValue = RawToPercentage(*prop, value);
|
percentageValue = RawToPercentage(*prop, value);
|
||||||
@@ -1320,7 +1050,7 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetProperty(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Actually set the new value on the device (if possible)
|
// Actually set the new value on the device (if possible)
|
||||||
if (!DeviceSetProperty(lock, *prop, value, valueStr))
|
if (!prop->DeviceSet(lock, m_fd, value, valueStr))
|
||||||
return CS_PROPERTY_WRITE_FAILED;
|
return CS_PROPERTY_WRITE_FAILED;
|
||||||
|
|
||||||
// Cache the set values
|
// Cache the set values
|
||||||
@@ -1391,7 +1121,7 @@ void UsbCameraImpl::Send(std::unique_ptr<Message> msg) const {
|
|||||||
|
|
||||||
std::unique_ptr<PropertyImpl> UsbCameraImpl::CreateEmptyProperty(
|
std::unique_ptr<PropertyImpl> UsbCameraImpl::CreateEmptyProperty(
|
||||||
llvm::StringRef name) const {
|
llvm::StringRef name) const {
|
||||||
return llvm::make_unique<PropertyData>(name);
|
return llvm::make_unique<UsbCameraProperty>(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UsbCameraImpl::CacheProperties(CS_Status* status) const {
|
bool UsbCameraImpl::CacheProperties(CS_Status* status) const {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "SourceImpl.h"
|
#include "SourceImpl.h"
|
||||||
#include "UsbCameraBuffer.h"
|
#include "UsbCameraBuffer.h"
|
||||||
|
#include "UsbCameraProperty.h"
|
||||||
|
|
||||||
namespace cs {
|
namespace cs {
|
||||||
|
|
||||||
@@ -49,43 +50,6 @@ class UsbCameraImpl : public SourceImpl {
|
|||||||
|
|
||||||
std::string GetPath() { return m_path; }
|
std::string GetPath() { return m_path; }
|
||||||
|
|
||||||
// Property data
|
|
||||||
class PropertyData : public PropertyImpl {
|
|
||||||
public:
|
|
||||||
PropertyData() = default;
|
|
||||||
PropertyData(llvm::StringRef name_) : PropertyImpl{name_} {}
|
|
||||||
|
|
||||||
// Normalized property constructor
|
|
||||||
PropertyData(llvm::StringRef name_, int rawIndex_,
|
|
||||||
const PropertyData& rawProp, int defaultValue_, int value_)
|
|
||||||
: PropertyImpl(name_, rawProp.propKind, 1, defaultValue_, value_),
|
|
||||||
percentage{true},
|
|
||||||
propPair{rawIndex_},
|
|
||||||
id{rawProp.id},
|
|
||||||
type{rawProp.type} {
|
|
||||||
hasMinimum = true;
|
|
||||||
minimum = 0;
|
|
||||||
hasMaximum = true;
|
|
||||||
maximum = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
#ifdef VIDIOC_QUERY_EXT_CTRL
|
|
||||||
PropertyData(const struct v4l2_query_ext_ctrl& ctrl);
|
|
||||||
#endif
|
|
||||||
PropertyData(const struct v4l2_queryctrl& ctrl);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// If this is a percentage (rather than raw) property
|
|
||||||
bool percentage{false};
|
|
||||||
|
|
||||||
// If not 0, index of corresponding raw/percentage property
|
|
||||||
int propPair{0};
|
|
||||||
|
|
||||||
unsigned id{0}; // implementation-level id
|
|
||||||
int type{0}; // implementation type, not CS_PropertyKind!
|
|
||||||
};
|
|
||||||
|
|
||||||
// Messages passed to/from camera thread
|
// Messages passed to/from camera thread
|
||||||
struct Message {
|
struct Message {
|
||||||
enum Kind {
|
enum Kind {
|
||||||
@@ -151,15 +115,9 @@ class UsbCameraImpl : public SourceImpl {
|
|||||||
void DeviceSetMode();
|
void DeviceSetMode();
|
||||||
void DeviceSetFPS();
|
void DeviceSetFPS();
|
||||||
void DeviceCacheMode();
|
void DeviceCacheMode();
|
||||||
void DeviceCacheProperty(std::unique_ptr<PropertyData> rawProp);
|
void DeviceCacheProperty(std::unique_ptr<UsbCameraProperty> rawProp);
|
||||||
void DeviceCacheProperties();
|
void DeviceCacheProperties();
|
||||||
void DeviceCacheVideoModes();
|
void DeviceCacheVideoModes();
|
||||||
bool DeviceGetProperty(PropertyData* prop);
|
|
||||||
bool DeviceSetProperty(std::unique_lock<std::mutex>& lock,
|
|
||||||
const PropertyData& prop);
|
|
||||||
bool DeviceSetProperty(std::unique_lock<std::mutex>& lock,
|
|
||||||
const PropertyData& prop, int value,
|
|
||||||
llvm::StringRef valueStr);
|
|
||||||
|
|
||||||
// Command helper functions
|
// Command helper functions
|
||||||
CS_StatusValue DeviceCmdSetProperty(std::unique_lock<std::mutex>& lock,
|
CS_StatusValue DeviceCmdSetProperty(std::unique_lock<std::mutex>& lock,
|
||||||
@@ -167,8 +125,8 @@ class UsbCameraImpl : public SourceImpl {
|
|||||||
llvm::StringRef valueStr);
|
llvm::StringRef valueStr);
|
||||||
|
|
||||||
// Property helper functions
|
// Property helper functions
|
||||||
int RawToPercentage(const PropertyData& rawProp, int rawValue);
|
int RawToPercentage(const UsbCameraProperty& rawProp, int rawValue);
|
||||||
int PercentageToRaw(const PropertyData& rawProp, int percentValue);
|
int PercentageToRaw(const UsbCameraProperty& rawProp, int percentValue);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Variables only used within camera thread
|
// Variables only used within camera thread
|
||||||
|
|||||||
277
src/UsbCameraProperty.cpp
Normal file
277
src/UsbCameraProperty.cpp
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||||
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||||
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||||
|
/* the project. */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "UsbCameraProperty.h"
|
||||||
|
|
||||||
|
#include "llvm/SmallString.h"
|
||||||
|
|
||||||
|
#include "UsbUtil.h"
|
||||||
|
|
||||||
|
using namespace cs;
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
static int GetIntCtrlIoctl(int fd, unsigned id, int type, int64_t* value) {
|
||||||
|
unsigned ctrl_class = V4L2_CTRL_ID2CLASS(id);
|
||||||
|
if (type == V4L2_CTRL_TYPE_INTEGER64 || V4L2_CTRL_DRIVER_PRIV(id) ||
|
||||||
|
(ctrl_class != V4L2_CTRL_CLASS_USER &&
|
||||||
|
ctrl_class != V4L2_CID_PRIVATE_BASE)) {
|
||||||
|
// Use extended control
|
||||||
|
struct v4l2_ext_control ctrl;
|
||||||
|
struct v4l2_ext_controls ctrls;
|
||||||
|
std::memset(&ctrl, 0, sizeof(ctrl));
|
||||||
|
std::memset(&ctrls, 0, sizeof(ctrls));
|
||||||
|
ctrl.id = id;
|
||||||
|
ctrls.ctrl_class = ctrl_class;
|
||||||
|
ctrls.count = 1;
|
||||||
|
ctrls.controls = &ctrl;
|
||||||
|
int rc = DoIoctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls);
|
||||||
|
if (rc < 0) return rc;
|
||||||
|
*value = ctrl.value;
|
||||||
|
} else {
|
||||||
|
// Use normal control
|
||||||
|
struct v4l2_control ctrl;
|
||||||
|
std::memset(&ctrl, 0, sizeof(ctrl));
|
||||||
|
ctrl.id = id;
|
||||||
|
int rc = DoIoctl(fd, VIDIOC_G_CTRL, &ctrl);
|
||||||
|
if (rc < 0) return rc;
|
||||||
|
*value = ctrl.value;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SetIntCtrlIoctl(int fd, unsigned id, int type, int64_t value) {
|
||||||
|
unsigned ctrl_class = V4L2_CTRL_ID2CLASS(id);
|
||||||
|
if (type == V4L2_CTRL_TYPE_INTEGER64 || V4L2_CTRL_DRIVER_PRIV(id) ||
|
||||||
|
(ctrl_class != V4L2_CTRL_CLASS_USER &&
|
||||||
|
ctrl_class != V4L2_CID_PRIVATE_BASE)) {
|
||||||
|
// Use extended control
|
||||||
|
struct v4l2_ext_control ctrl;
|
||||||
|
struct v4l2_ext_controls ctrls;
|
||||||
|
std::memset(&ctrl, 0, sizeof(ctrl));
|
||||||
|
std::memset(&ctrls, 0, sizeof(ctrls));
|
||||||
|
ctrl.id = id;
|
||||||
|
if (type == V4L2_CTRL_TYPE_INTEGER64)
|
||||||
|
ctrl.value64 = value;
|
||||||
|
else
|
||||||
|
ctrl.value = static_cast<__s32>(value);
|
||||||
|
ctrls.ctrl_class = ctrl_class;
|
||||||
|
ctrls.count = 1;
|
||||||
|
ctrls.controls = &ctrl;
|
||||||
|
return DoIoctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
|
||||||
|
} else {
|
||||||
|
// Use normal control
|
||||||
|
struct v4l2_control ctrl;
|
||||||
|
ctrl.id = id;
|
||||||
|
ctrl.value = static_cast<__s32>(value);
|
||||||
|
return DoIoctl(fd, VIDIOC_S_CTRL, &ctrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GetStringCtrlIoctl(int fd, int id, int maximum,
|
||||||
|
std::string* value) {
|
||||||
|
struct v4l2_ext_control ctrl;
|
||||||
|
struct v4l2_ext_controls ctrls;
|
||||||
|
std::memset(&ctrl, 0, sizeof(ctrl));
|
||||||
|
std::memset(&ctrls, 0, sizeof(ctrls));
|
||||||
|
ctrl.id = id;
|
||||||
|
ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(id);
|
||||||
|
ctrls.count = 1;
|
||||||
|
ctrls.controls = &ctrl;
|
||||||
|
int rc = DoIoctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls);
|
||||||
|
if (rc < 0) {
|
||||||
|
value->clear();
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
value->assign(ctrl.string, std::strlen(ctrl.string));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SetStringCtrlIoctl(int fd, int id, int maximum,
|
||||||
|
llvm::StringRef value) {
|
||||||
|
llvm::SmallString<64> str{value.substr(
|
||||||
|
0, std::min(value.size(), static_cast<std::size_t>(maximum)))};
|
||||||
|
|
||||||
|
struct v4l2_ext_control ctrl;
|
||||||
|
struct v4l2_ext_controls ctrls;
|
||||||
|
std::memset(&ctrl, 0, sizeof(ctrl));
|
||||||
|
std::memset(&ctrls, 0, sizeof(ctrls));
|
||||||
|
ctrl.id = id;
|
||||||
|
ctrl.size = str.size();
|
||||||
|
ctrl.string = const_cast<char*>(str.c_str());
|
||||||
|
ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(id);
|
||||||
|
ctrls.count = 1;
|
||||||
|
ctrls.controls = &ctrl;
|
||||||
|
return DoIoctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes non-alphanumeric characters and replaces spaces with underscores.
|
||||||
|
// e.g. "Zoom, Absolute" -> "zoom_absolute", "Pan (Absolute)" -> "pan_absolute"
|
||||||
|
static llvm::StringRef NormalizeName(llvm::StringRef name,
|
||||||
|
llvm::SmallVectorImpl<char>& buf) {
|
||||||
|
bool newWord = false;
|
||||||
|
for (auto ch : name) {
|
||||||
|
if (std::isalnum(ch)) {
|
||||||
|
if (newWord) buf.push_back('_');
|
||||||
|
newWord = false;
|
||||||
|
buf.push_back(std::tolower(ch));
|
||||||
|
} else if (!buf.empty())
|
||||||
|
newWord = true;
|
||||||
|
}
|
||||||
|
return llvm::StringRef(buf.data(), buf.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VIDIOC_QUERY_EXT_CTRL
|
||||||
|
UsbCameraProperty::UsbCameraProperty(const struct v4l2_query_ext_ctrl& ctrl)
|
||||||
|
: PropertyImpl(llvm::StringRef{}, CS_PROP_NONE, ctrl.step,
|
||||||
|
ctrl.default_value, 0),
|
||||||
|
id(ctrl.id & V4L2_CTRL_ID_MASK),
|
||||||
|
type(ctrl.type) {
|
||||||
|
hasMinimum = true;
|
||||||
|
minimum = ctrl.minimum;
|
||||||
|
hasMaximum = true;
|
||||||
|
maximum = ctrl.maximum;
|
||||||
|
|
||||||
|
// propKind
|
||||||
|
switch (ctrl.type) {
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER:
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER64:
|
||||||
|
propKind = CS_PROP_INTEGER;
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_BOOLEAN:
|
||||||
|
propKind = CS_PROP_BOOLEAN;
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
||||||
|
case V4L2_CTRL_TYPE_MENU:
|
||||||
|
propKind = CS_PROP_ENUM;
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_STRING:
|
||||||
|
propKind = CS_PROP_STRING;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return; // others unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
// name
|
||||||
|
std::size_t len = 0;
|
||||||
|
while (len < sizeof(ctrl.name) && ctrl.name[len] != '\0') ++len;
|
||||||
|
llvm::SmallString<64> name_buf;
|
||||||
|
name = NormalizeName(llvm::StringRef(ctrl.name, len), name_buf);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UsbCameraProperty::UsbCameraProperty(const struct v4l2_queryctrl& ctrl)
|
||||||
|
: PropertyImpl(llvm::StringRef{}, CS_PROP_NONE, ctrl.step,
|
||||||
|
ctrl.default_value, 0),
|
||||||
|
id(ctrl.id & V4L2_CTRL_ID_MASK),
|
||||||
|
type(ctrl.type) {
|
||||||
|
hasMinimum = true;
|
||||||
|
minimum = ctrl.minimum;
|
||||||
|
hasMaximum = true;
|
||||||
|
maximum = ctrl.maximum;
|
||||||
|
|
||||||
|
// propKind
|
||||||
|
switch (ctrl.type) {
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER:
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER64:
|
||||||
|
propKind = CS_PROP_INTEGER;
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_BOOLEAN:
|
||||||
|
propKind = CS_PROP_BOOLEAN;
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
||||||
|
case V4L2_CTRL_TYPE_MENU:
|
||||||
|
propKind = CS_PROP_ENUM;
|
||||||
|
break;
|
||||||
|
case V4L2_CTRL_TYPE_STRING:
|
||||||
|
propKind = CS_PROP_STRING;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return; // others unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
// name
|
||||||
|
std::size_t len = 0;
|
||||||
|
while (len < sizeof(ctrl.name) && ctrl.name[len] != '\0') ++len;
|
||||||
|
llvm::SmallString<64> name_buf;
|
||||||
|
name = NormalizeName(
|
||||||
|
llvm::StringRef(reinterpret_cast<const char*>(ctrl.name), len), name_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsbCameraProperty::DeviceGet(std::unique_lock<std::mutex>& lock, int fd) {
|
||||||
|
if (fd < 0) return true;
|
||||||
|
unsigned idCopy = id;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
switch (propKind) {
|
||||||
|
case CS_PROP_BOOLEAN:
|
||||||
|
case CS_PROP_INTEGER:
|
||||||
|
case CS_PROP_ENUM: {
|
||||||
|
int typeCopy = type;
|
||||||
|
int64_t newValue = 0;
|
||||||
|
lock.unlock();
|
||||||
|
rv = GetIntCtrlIoctl(fd, idCopy, typeCopy, &newValue);
|
||||||
|
lock.lock();
|
||||||
|
if (rv >= 0) value = newValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CS_PROP_STRING: {
|
||||||
|
int maximumCopy = maximum;
|
||||||
|
std::string newValueStr;
|
||||||
|
lock.unlock();
|
||||||
|
rv = GetStringCtrlIoctl(fd, idCopy, maximumCopy, &newValueStr);
|
||||||
|
lock.lock();
|
||||||
|
if (rv >= 0) valueStr = std::move(newValueStr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsbCameraProperty::DeviceSet(std::unique_lock<std::mutex>& lock,
|
||||||
|
int fd) const {
|
||||||
|
// Make a copy of the string as we're about to release the lock
|
||||||
|
llvm::SmallString<128> valueStrCopy{valueStr};
|
||||||
|
return DeviceSet(lock, fd, value, valueStrCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsbCameraProperty::DeviceSet(std::unique_lock<std::mutex>& lock, int fd,
|
||||||
|
int newValue,
|
||||||
|
llvm::StringRef newValueStr) const {
|
||||||
|
if (fd < 0) return true;
|
||||||
|
unsigned idCopy = id;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
switch (propKind) {
|
||||||
|
case CS_PROP_BOOLEAN:
|
||||||
|
case CS_PROP_INTEGER:
|
||||||
|
case CS_PROP_ENUM: {
|
||||||
|
int typeCopy = type;
|
||||||
|
lock.unlock();
|
||||||
|
rv = SetIntCtrlIoctl(fd, idCopy, typeCopy, newValue);
|
||||||
|
lock.lock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CS_PROP_STRING: {
|
||||||
|
int maximumCopy = maximum;
|
||||||
|
lock.unlock();
|
||||||
|
rv = SetStringCtrlIoctl(fd, idCopy, maximumCopy, newValueStr);
|
||||||
|
lock.lock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __linux__
|
||||||
66
src/UsbCameraProperty.h
Normal file
66
src/UsbCameraProperty.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||||
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||||
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||||
|
/* the project. */
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef CS_USBCAMERAPROPERTY_H_
|
||||||
|
#define CS_USBCAMERAPROPERTY_H_
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "PropertyImpl.h"
|
||||||
|
|
||||||
|
namespace cs {
|
||||||
|
|
||||||
|
// Property data
|
||||||
|
class UsbCameraProperty : public PropertyImpl {
|
||||||
|
public:
|
||||||
|
UsbCameraProperty() = default;
|
||||||
|
UsbCameraProperty(llvm::StringRef name_) : PropertyImpl{name_} {}
|
||||||
|
|
||||||
|
// Normalized property constructor
|
||||||
|
UsbCameraProperty(llvm::StringRef name_, int rawIndex_,
|
||||||
|
const UsbCameraProperty& rawProp, int defaultValue_,
|
||||||
|
int value_)
|
||||||
|
: PropertyImpl(name_, rawProp.propKind, 1, defaultValue_, value_),
|
||||||
|
percentage{true},
|
||||||
|
propPair{rawIndex_},
|
||||||
|
id{rawProp.id},
|
||||||
|
type{rawProp.type} {
|
||||||
|
hasMinimum = true;
|
||||||
|
minimum = 0;
|
||||||
|
hasMaximum = true;
|
||||||
|
maximum = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#ifdef VIDIOC_QUERY_EXT_CTRL
|
||||||
|
UsbCameraProperty(const struct v4l2_query_ext_ctrl& ctrl);
|
||||||
|
#endif
|
||||||
|
UsbCameraProperty(const struct v4l2_queryctrl& ctrl);
|
||||||
|
|
||||||
|
bool DeviceGet(std::unique_lock<std::mutex>& lock, int fd);
|
||||||
|
bool DeviceSet(std::unique_lock<std::mutex>& lock, int fd) const;
|
||||||
|
bool DeviceSet(std::unique_lock<std::mutex>& lock, int fd, int newValue,
|
||||||
|
llvm::StringRef newValueStr) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If this is a percentage (rather than raw) property
|
||||||
|
bool percentage{false};
|
||||||
|
|
||||||
|
// If not 0, index of corresponding raw/percentage property
|
||||||
|
int propPair{0};
|
||||||
|
|
||||||
|
unsigned id{0}; // implementation-level id
|
||||||
|
int type{0}; // implementation type, not CS_PropertyKind!
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cs
|
||||||
|
|
||||||
|
#endif // CS_USBCAMERAPROPERTY_H_
|
||||||
@@ -8,6 +8,10 @@
|
|||||||
#include "UsbUtil.h"
|
#include "UsbUtil.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "llvm/Format.h"
|
#include "llvm/Format.h"
|
||||||
#include "llvm/SmallString.h"
|
#include "llvm/SmallString.h"
|
||||||
@@ -15,6 +19,7 @@
|
|||||||
#include "support/raw_istream.h"
|
#include "support/raw_istream.h"
|
||||||
|
|
||||||
#include "HttpUtil.h"
|
#include "HttpUtil.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
namespace cs {
|
namespace cs {
|
||||||
|
|
||||||
@@ -105,4 +110,20 @@ llvm::StringRef GetUsbNameFromId(int vendor, int product,
|
|||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
int CheckedIoctl(int fd, unsigned long req, void* data, const char* name,
|
||||||
|
const char* file, int line, bool quiet) {
|
||||||
|
int retval = ioctl(fd, req, data);
|
||||||
|
if (!quiet && retval < 0) {
|
||||||
|
llvm::SmallString<64> localfile{file};
|
||||||
|
localfile.push_back('\0');
|
||||||
|
ERROR("ioctl " << name << " failed at " << basename(localfile.data()) << ":"
|
||||||
|
<< line << ": " << std::strerror(errno));
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
} // namespace cs
|
} // namespace cs
|
||||||
|
|||||||
@@ -16,6 +16,17 @@ namespace cs {
|
|||||||
llvm::StringRef GetUsbNameFromId(int vendor, int product,
|
llvm::StringRef GetUsbNameFromId(int vendor, int product,
|
||||||
llvm::SmallVectorImpl<char>& buf);
|
llvm::SmallVectorImpl<char>& buf);
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
int CheckedIoctl(int fd, unsigned long req, void* data, const char* name,
|
||||||
|
const char* file, int line, bool quiet);
|
||||||
|
|
||||||
|
#define DoIoctl(fd, req, data) \
|
||||||
|
CheckedIoctl(fd, req, data, #req, __FILE__, __LINE__, false)
|
||||||
|
#define TryIoctl(fd, req, data) \
|
||||||
|
CheckedIoctl(fd, req, data, #req, __FILE__, __LINE__, true)
|
||||||
|
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
} // namespace cs
|
} // namespace cs
|
||||||
|
|
||||||
#endif // CS_USBUTIL_H_
|
#endif // CS_USBUTIL_H_
|
||||||
|
|||||||
Reference in New Issue
Block a user