2020-12-26 14:12:05 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2019-05-30 19:12:05 -07:00
|
|
|
|
|
|
|
|
#include "ConfigurableSourceImpl.h"
|
|
|
|
|
|
|
|
|
|
#include <wpi/timestamp.h>
|
|
|
|
|
|
|
|
|
|
#include "Handle.h"
|
|
|
|
|
#include "Instance.h"
|
|
|
|
|
#include "Log.h"
|
|
|
|
|
#include "Notifier.h"
|
|
|
|
|
|
|
|
|
|
using namespace cs;
|
|
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
ConfigurableSourceImpl::ConfigurableSourceImpl(std::string_view name,
|
2019-05-30 19:12:05 -07:00
|
|
|
wpi::Logger& logger,
|
|
|
|
|
Notifier& notifier,
|
|
|
|
|
Telemetry& telemetry,
|
|
|
|
|
const VideoMode& mode)
|
|
|
|
|
: SourceImpl{name, logger, notifier, telemetry} {
|
|
|
|
|
m_mode = mode;
|
|
|
|
|
m_videoModes.push_back(m_mode);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-28 00:37:33 -08:00
|
|
|
ConfigurableSourceImpl::~ConfigurableSourceImpl() = default;
|
2019-05-30 19:12:05 -07:00
|
|
|
|
|
|
|
|
void ConfigurableSourceImpl::Start() {
|
|
|
|
|
m_notifier.NotifySource(*this, CS_SOURCE_CONNECTED);
|
|
|
|
|
m_notifier.NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
|
|
|
|
|
m_notifier.NotifySourceVideoMode(*this, m_mode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ConfigurableSourceImpl::SetVideoMode(const VideoMode& mode,
|
|
|
|
|
CS_Status* status) {
|
|
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_mutex);
|
2019-05-30 19:12:05 -07:00
|
|
|
m_mode = mode;
|
|
|
|
|
m_videoModes[0] = mode;
|
|
|
|
|
}
|
|
|
|
|
m_notifier.NotifySourceVideoMode(*this, mode);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ConfigurableSourceImpl::NumSinksChanged() {
|
|
|
|
|
// ignore
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ConfigurableSourceImpl::NumSinksEnabledChanged() {
|
|
|
|
|
// ignore
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
void ConfigurableSourceImpl::NotifyError(std::string_view msg) {
|
2019-05-30 19:12:05 -07:00
|
|
|
PutError(msg, wpi::Now());
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
int ConfigurableSourceImpl::CreateProperty(std::string_view name,
|
2019-05-30 19:12:05 -07:00
|
|
|
CS_PropertyKind kind, int minimum,
|
|
|
|
|
int maximum, int step,
|
|
|
|
|
int defaultValue, int value) {
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_mutex);
|
2020-06-27 20:39:00 -07:00
|
|
|
int ndx = CreateOrUpdateProperty(
|
|
|
|
|
name,
|
|
|
|
|
[=] {
|
|
|
|
|
return std::make_unique<PropertyImpl>(name, kind, minimum, maximum,
|
|
|
|
|
step, defaultValue, value);
|
|
|
|
|
},
|
|
|
|
|
[&](PropertyImpl& prop) {
|
|
|
|
|
// update all but value
|
|
|
|
|
prop.propKind = kind;
|
|
|
|
|
prop.minimum = minimum;
|
|
|
|
|
prop.maximum = maximum;
|
|
|
|
|
prop.step = step;
|
|
|
|
|
prop.defaultValue = defaultValue;
|
|
|
|
|
value = prop.value;
|
|
|
|
|
});
|
2019-05-30 19:12:05 -07:00
|
|
|
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name, ndx,
|
2021-06-06 16:13:58 -07:00
|
|
|
kind, value, {});
|
2019-05-30 19:12:05 -07:00
|
|
|
return ndx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ConfigurableSourceImpl::CreateProperty(
|
2021-06-06 16:13:58 -07:00
|
|
|
std::string_view name, CS_PropertyKind kind, int minimum, int maximum,
|
2019-05-30 19:12:05 -07:00
|
|
|
int step, int defaultValue, int value,
|
|
|
|
|
std::function<void(CS_Property property)> onChange) {
|
|
|
|
|
// TODO
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ConfigurableSourceImpl::SetEnumPropertyChoices(
|
2022-10-15 16:33:14 -07:00
|
|
|
int property, std::span<const std::string> choices, CS_Status* status) {
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_mutex);
|
2019-05-30 19:12:05 -07:00
|
|
|
auto prop = GetProperty(property);
|
|
|
|
|
if (!prop) {
|
|
|
|
|
*status = CS_INVALID_PROPERTY;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (prop->propKind != CS_PROP_ENUM) {
|
|
|
|
|
*status = CS_WRONG_PROPERTY_TYPE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-06-06 19:51:14 -07:00
|
|
|
prop->enumChoices.assign(choices.begin(), choices.end());
|
2019-05-30 19:12:05 -07:00
|
|
|
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
|
|
|
|
prop->name, property, CS_PROP_ENUM,
|
2021-06-06 16:13:58 -07:00
|
|
|
prop->value, {});
|
2019-05-30 19:12:05 -07:00
|
|
|
}
|
2024-02-12 22:33:03 -08:00
|
|
|
|
|
|
|
|
namespace cs {
|
|
|
|
|
static constexpr unsigned SourceMask = CS_SOURCE_CV | CS_SOURCE_RAW;
|
|
|
|
|
|
|
|
|
|
void NotifySourceError(CS_Source source, std::string_view msg,
|
|
|
|
|
CS_Status* status) {
|
|
|
|
|
auto data = Instance::GetInstance().GetSource(source);
|
|
|
|
|
if (!data || (data->kind & SourceMask) == 0) {
|
|
|
|
|
*status = CS_INVALID_HANDLE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
static_cast<ConfigurableSourceImpl&>(*data->source).NotifyError(msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) {
|
|
|
|
|
auto data = Instance::GetInstance().GetSource(source);
|
|
|
|
|
if (!data || (data->kind & SourceMask) == 0) {
|
|
|
|
|
*status = CS_INVALID_HANDLE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
static_cast<ConfigurableSourceImpl&>(*data->source).SetConnected(connected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetSourceDescription(CS_Source source, std::string_view description,
|
|
|
|
|
CS_Status* status) {
|
|
|
|
|
auto data = Instance::GetInstance().GetSource(source);
|
|
|
|
|
if (!data || (data->kind & SourceMask) == 0) {
|
|
|
|
|
*status = CS_INVALID_HANDLE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
static_cast<ConfigurableSourceImpl&>(*data->source)
|
|
|
|
|
.SetDescription(description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CS_Property CreateSourceProperty(CS_Source source, std::string_view name,
|
|
|
|
|
CS_PropertyKind kind, int minimum, int maximum,
|
|
|
|
|
int step, int defaultValue, int value,
|
|
|
|
|
CS_Status* status) {
|
|
|
|
|
auto data = Instance::GetInstance().GetSource(source);
|
|
|
|
|
if (!data || (data->kind & SourceMask) == 0) {
|
|
|
|
|
*status = CS_INVALID_HANDLE;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
int property = static_cast<ConfigurableSourceImpl&>(*data->source)
|
|
|
|
|
.CreateProperty(name, kind, minimum, maximum, step,
|
|
|
|
|
defaultValue, value);
|
|
|
|
|
return Handle{source, property, Handle::kProperty};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CS_Property CreateSourcePropertyCallback(
|
|
|
|
|
CS_Source source, std::string_view name, CS_PropertyKind kind, int minimum,
|
|
|
|
|
int maximum, int step, int defaultValue, int value,
|
|
|
|
|
std::function<void(CS_Property property)> onChange, CS_Status* status) {
|
|
|
|
|
auto data = Instance::GetInstance().GetSource(source);
|
|
|
|
|
if (!data || (data->kind & SourceMask) == 0) {
|
|
|
|
|
*status = CS_INVALID_HANDLE;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
int property = static_cast<ConfigurableSourceImpl&>(*data->source)
|
|
|
|
|
.CreateProperty(name, kind, minimum, maximum, step,
|
|
|
|
|
defaultValue, value, onChange);
|
|
|
|
|
return Handle{source, property, Handle::kProperty};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
|
|
|
|
|
std::span<const std::string> choices,
|
|
|
|
|
CS_Status* status) {
|
|
|
|
|
auto data = Instance::GetInstance().GetSource(source);
|
|
|
|
|
if (!data || (data->kind & SourceMask) == 0) {
|
|
|
|
|
*status = CS_INVALID_HANDLE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get property index; also validate the source owns this property
|
|
|
|
|
Handle handle{property};
|
|
|
|
|
int i = handle.GetParentIndex();
|
|
|
|
|
if (i < 0) {
|
|
|
|
|
*status = CS_INVALID_HANDLE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto data2 = Instance::GetInstance().GetSource(Handle{i, Handle::kSource});
|
|
|
|
|
if (!data2 || data->source.get() != data2->source.get()) {
|
|
|
|
|
*status = CS_INVALID_HANDLE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int propertyIndex = handle.GetIndex();
|
|
|
|
|
static_cast<ConfigurableSourceImpl&>(*data->source)
|
|
|
|
|
.SetEnumPropertyChoices(propertyIndex, choices, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace cs
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
void CS_NotifySourceError(CS_Source source, const char* msg,
|
|
|
|
|
CS_Status* status) {
|
|
|
|
|
return cs::NotifySourceError(source, msg, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CS_SetSourceConnected(CS_Source source, CS_Bool connected,
|
|
|
|
|
CS_Status* status) {
|
|
|
|
|
return cs::SetSourceConnected(source, connected, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CS_SetSourceDescription(CS_Source source, const char* description,
|
|
|
|
|
CS_Status* status) {
|
|
|
|
|
return cs::SetSourceDescription(source, description, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CS_Property CS_CreateSourceProperty(CS_Source source, const char* name,
|
|
|
|
|
enum CS_PropertyKind kind, int minimum,
|
|
|
|
|
int maximum, int step, int defaultValue,
|
|
|
|
|
int value, CS_Status* status) {
|
|
|
|
|
return cs::CreateSourceProperty(source, name, kind, minimum, maximum, step,
|
|
|
|
|
defaultValue, value, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CS_Property CS_CreateSourcePropertyCallback(
|
|
|
|
|
CS_Source source, const char* name, enum CS_PropertyKind kind, int minimum,
|
|
|
|
|
int maximum, int step, int defaultValue, int value, void* data,
|
|
|
|
|
void (*onChange)(void* data, CS_Property property), CS_Status* status) {
|
|
|
|
|
return cs::CreateSourcePropertyCallback(
|
|
|
|
|
source, name, kind, minimum, maximum, step, defaultValue, value,
|
|
|
|
|
[=](CS_Property property) { onChange(data, property); }, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CS_SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
|
|
|
|
|
const char** choices, int count,
|
|
|
|
|
CS_Status* status) {
|
|
|
|
|
wpi::SmallVector<std::string, 8> vec;
|
|
|
|
|
vec.reserve(count);
|
|
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
|
vec.push_back(choices[i]);
|
|
|
|
|
}
|
|
|
|
|
return cs::SetSourceEnumPropertyChoices(source, property, vec, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // extern "C"
|