blob: fa74145723c99ac47ef46e0bfda66b61e85b1d52 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "adc-buttons-device.h"
#include <lib/driver/logging/cpp/structured_logger.h>
#include <lib/zx/clock.h>
namespace adc_buttons_device {
void AdcButtonsDevice::AdcButtonInputReport::ToFidlInputReport(
fidl::WireTableBuilder<::fuchsia_input_report::wire::InputReport>& input_report,
fidl::AnyArena& allocator) {
fidl::VectorView<fuchsia_input_report::wire::ConsumerControlButton> pressed_buttons_rpt(
allocator, buttons.size());
std::copy(buttons.begin(), buttons.end(), pressed_buttons_rpt.begin());
auto consumer_control_report =
fuchsia_input_report::wire::ConsumerControlInputReport::Builder(allocator).pressed_buttons(
pressed_buttons_rpt);
input_report.event_time(event_time.get()).consumer_control(consumer_control_report.Build());
}
void AdcButtonsDevice::PollingTask(async_dispatcher_t* dispatcher, async::TaskBase* task,
zx_status_t status) {
if (status != ZX_OK) {
return;
}
polling_task_.PostDelayed(dispatcher_, zx::usec(polling_rate_usec_));
auto report = GetInputReport();
if (report.is_error()) {
FDF_LOG(ERROR, "Failed to get report %d", report.error_value());
return;
}
if (rpt_.has_value() && rpt_->buttons == report->buttons) {
return;
}
rpt_ = std::move(*report);
readers_.SendReportToAllReaders(*rpt_);
}
zx::result<AdcButtonsDevice::AdcButtonInputReport> AdcButtonsDevice::GetInputReport() {
std::set<fuchsia_input_report::ConsumerControlButton> buttons;
for (const auto& client : clients_) {
auto result = client.adc_->GetSample();
if (!result.ok()) {
FDF_LOG(ERROR, "%s: GetSample failed %s", __func__, result.FormatDescription().c_str());
return zx::error(ZX_ERR_INTERNAL);
}
if (result->is_error()) {
FDF_LOG(ERROR, "%s: GetSample failed %d", __func__, result->error_value());
return zx::error(result->error_value());
}
for (const auto& cfg : client.buttons_) {
const auto& saradc = cfg.button_config()->adc();
if (result.value()->value >= saradc->press_threshold() &&
result.value()->value < saradc->release_threshold()) {
buttons.insert(cfg.types()->begin(), cfg.types()->end());
}
}
}
ZX_DEBUG_ASSERT_MSG(
buttons.size() <= fuchsia_input_report::kConsumerControlMaxNumButtons,
"More buttons than expected (max = %d). Please increase kConsumerControlMaxNumButtons ",
fuchsia_input_report::kConsumerControlMaxNumButtons);
return zx::ok(AdcButtonInputReport{
.event_time = zx::clock::get_monotonic(),
.buttons = std::move(buttons),
});
}
void AdcButtonsDevice::GetInputReportsReader(GetInputReportsReaderRequestView request,
GetInputReportsReaderCompleter::Sync& completer) {
auto initial_report = GetInputReport();
if (initial_report.is_error()) {
FDF_LOG(ERROR, "Failed to get initial report %d", initial_report.error_value());
}
auto status = readers_.CreateReader(
dispatcher_, std::move(request->reader),
initial_report.is_ok() ? std::make_optional(initial_report.value()) : std::nullopt);
if (status != ZX_OK) {
FDF_LOG(ERROR, "%s: CreateReader failed %d", __func__, status);
}
}
void AdcButtonsDevice::GetDescriptor(GetDescriptorCompleter::Sync& completer) {
fidl::Arena<kFeatureAndDescriptorBufferSize> allocator;
auto device_info = fuchsia_input_report::wire::DeviceInformation::Builder(allocator);
device_info.vendor_id(static_cast<uint32_t>(fuchsia_input_report::wire::VendorId::kGoogle));
device_info.product_id(
static_cast<uint32_t>(fuchsia_input_report::wire::VendorGoogleProductId::kAdcButtons));
device_info.polling_rate(polling_rate_usec_);
fidl::VectorView<fuchsia_input_report::wire::ConsumerControlButton> buttons(allocator,
buttons_.size());
std::copy(buttons_.begin(), buttons_.end(), buttons.begin());
const auto input = fuchsia_input_report::wire::ConsumerControlInputDescriptor::Builder(allocator)
.buttons(buttons)
.Build();
const auto consumer_control =
fuchsia_input_report::wire::ConsumerControlDescriptor::Builder(allocator)
.input(input)
.Build();
const auto descriptor = fuchsia_input_report::wire::DeviceDescriptor::Builder(allocator)
.device_information(device_info.Build())
.consumer_control(consumer_control)
.Build();
completer.Reply(descriptor);
}
void AdcButtonsDevice::Shutdown() { polling_task_.Cancel(); }
} // namespace adc_buttons_device