diff --git a/base/cvd/cuttlefish/common/libs/sensors/sensors.h b/base/cvd/cuttlefish/common/libs/sensors/sensors.h index 789830d76d4..14124eab715 100644 --- a/base/cvd/cuttlefish/common/libs/sensors/sensors.h +++ b/base/cvd/cuttlefish/common/libs/sensors/sensors.h @@ -57,6 +57,7 @@ inline constexpr char OUTER_DELIM = ' '; inline constexpr int kUpdateRotationVec = 0; inline constexpr int kGetSensorsData = 1; inline constexpr int kUpdateHal = 2; +inline constexpr int kUpdateHingeAngle = 3; using SensorsCmd = int; diff --git a/base/cvd/cuttlefish/host/commands/sensors_simulator/main.cpp b/base/cvd/cuttlefish/host/commands/sensors_simulator/main.cpp index 9bb02b35389..3c8ea00b10b 100644 --- a/base/cvd/cuttlefish/host/commands/sensors_simulator/main.cpp +++ b/base/cvd/cuttlefish/host/commands/sensors_simulator/main.cpp @@ -60,7 +60,13 @@ Result ProcessWebrtcRequest(transport::SharedFdChannel& channel, CF_EXPECT((ss >> y >> delimiter) && (delimiter == INNER_DELIM), kReqMisFormatted); CF_EXPECT(static_cast(ss >> z), kReqMisFormatted); - sensors_simulator.RefreshSensors(x, y, z); + sensors_simulator.SetMotion(x, y, z); + break; + } + case kUpdateHingeAngle: { + float angle; + CF_EXPECT(static_cast(ss >> angle), kReqMisFormatted); + sensors_simulator.SetHingeAngle(angle); break; } case kGetSensorsData: { diff --git a/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_hal_proxy.cpp b/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_hal_proxy.cpp index f155d9ae037..423874f4398 100644 --- a/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_hal_proxy.cpp +++ b/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_hal_proxy.cpp @@ -16,6 +16,9 @@ #include "cuttlefish/host/commands/sensors_simulator/sensors_hal_proxy.h" +#include +#include + #include "absl/log/check.h" #include "absl/log/log.h" @@ -35,6 +38,13 @@ static constexpr SensorsMask kContinuousModeSensors = (1 << kPressureId) | (1 << kUncalibGyroscopeId) | (1 << kUncalibAccelerationId) | (1 << kLightId); +/* + On-change sensors are only reported to the guest when their value changes + (and once after the guest HAL (re)starts), instead of being streamed every + cycle like the continuous mode sensors above. +*/ +static constexpr SensorsMask kOnChangeSensors = (1 << kHingeAngle0Id); + Result SensorIdToName(int id) { switch (id) { case kAccelerationId: @@ -162,6 +172,10 @@ SensorsHalProxy::SensorsHalProxy(SharedFD control_from_guest_fd, sensors_simulator_(sensors_simulator) { const SensorsMask host_enabled_sensors = HostEnabledSensors(device_type); + sensors_simulator_.SetSensorsChangedCallback( + host_enabled_sensors & kOnChangeSensors, + [this](SensorsMask changed) { ReportToGuest(changed); }); + req_responder_thread_ = std::thread([this, host_enabled_sensors] { while (running_) { auto result = ProcessHalRequest(control_channel_, hal_activated_, @@ -174,18 +188,7 @@ SensorsHalProxy::SensorsHalProxy(SharedFD control_from_guest_fd, }); data_reporter_thread_ = std::thread([this, host_enabled_sensors] { while (running_) { - if (hal_activated_) { - SensorsMask host_update_sensors = - host_enabled_sensors & kContinuousModeSensors; - auto sensors_data = - sensors_simulator_.GetSensorsData(host_update_sensors); - auto result = - UpdateSensorsHal(sensors_data, data_channel_, host_update_sensors); - if (!result.ok()) { - running_ = false; - LOG(ERROR) << result.error(); - } - } + ReportToGuest(host_enabled_sensors & kContinuousModeSensors); std::this_thread::sleep_for(std::chrono::milliseconds(kIntervalMs)); } }); @@ -201,5 +204,18 @@ SensorsHalProxy::SensorsHalProxy(SharedFD control_from_guest_fd, }); } +void SensorsHalProxy::ReportToGuest(SensorsMask mask) { + if (!hal_activated_ || !mask) { + return; + } + std::string sensors_data = sensors_simulator_.GetSensorsData(mask); + std::lock_guard lock(report_mtx_); + auto result = UpdateSensorsHal(sensors_data, data_channel_, mask); + if (!result.ok()) { + running_ = false; + LOG(ERROR) << result.error(); + } +} + } // namespace sensors } // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_hal_proxy.h b/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_hal_proxy.h index 7bfdf080f14..316622e46f7 100644 --- a/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_hal_proxy.h +++ b/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_hal_proxy.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include "cuttlefish/common/libs/sensors/sensors.h" @@ -37,6 +38,8 @@ class SensorsHalProxy { SensorsSimulator& sensors_simulator, DeviceType device_type); private: + void ReportToGuest(SensorsMask mask); + std::thread req_responder_thread_; std::thread data_reporter_thread_; std::thread reboot_monitor_thread_; @@ -46,6 +49,7 @@ class SensorsHalProxy { SensorsSimulator& sensors_simulator_; std::atomic hal_activated_ = false; std::atomic running_ = true; + std::mutex report_mtx_; }; } // namespace sensors diff --git a/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_simulator.cpp b/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_simulator.cpp index 42f086d0f2b..fac950fabef 100644 --- a/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_simulator.cpp +++ b/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_simulator.cpp @@ -17,6 +17,7 @@ #include "cuttlefish/host/commands/sensors_simulator/sensors_simulator.h" #include +#include namespace cuttlefish { namespace sensors { @@ -96,7 +97,7 @@ SensorsSimulator::SensorsSimulator(bool is_auto) last_event_timestamp_(std::chrono::high_resolution_clock::now()), is_auto_(is_auto) { // Initialize sensors_data_ based on rotation vector = (0, 0, 0) - RefreshSensors(0, 0, 0); + SetMotion(0, 0, 0); // Set constant values for the sensors that are independent of rotation vector sensors_data_[kTemperatureId].f = kTemperature; sensors_data_[kProximityId].f = kProximity; @@ -106,30 +107,60 @@ SensorsSimulator::SensorsSimulator(bool is_auto) sensors_data_[kHingeAngle0Id].f = kHingeAngle0; } -void SensorsSimulator::RefreshSensors(double x, double y, double z) { +void SensorsSimulator::SetSensorsChangedCallback( + SensorsMask mask, SensorsChangedCallback callback) { + sensors_changed_mask_ = mask; + sensors_changed_callback_ = std::move(callback); +} + +void SensorsSimulator::NotifySensorsChanged(SensorsMask changed) { + SensorsMask relevant = changed & sensors_changed_mask_; + if (sensors_changed_callback_ && relevant) { + sensors_changed_callback_(relevant); + } +} + +void SensorsSimulator::SetMotion(double x, double y, double z) { auto rotation_matrix_update = GetRotationMatrix(x, y, z); auto acc_update = CalculateAcceleration(rotation_matrix_update, is_auto_); auto mgn_update = CalculateMagnetometer(rotation_matrix_update); - std::lock_guard lock(sensors_data_mtx_); - auto current_time = std::chrono::high_resolution_clock::now(); - auto duration = current_time - last_event_timestamp_; - last_event_timestamp_ = current_time; + { + std::lock_guard lock(sensors_data_mtx_); + auto current_time = std::chrono::high_resolution_clock::now(); + auto duration = current_time - last_event_timestamp_; + last_event_timestamp_ = current_time; - auto gyro_update = CalculateGyroscope(duration, current_rotation_matrix_, - rotation_matrix_update); + auto gyro_update = CalculateGyroscope(duration, current_rotation_matrix_, + rotation_matrix_update); - current_rotation_matrix_ = rotation_matrix_update; + current_rotation_matrix_ = rotation_matrix_update; - sensors_data_[kRotationVecId].v << x, y, z; - sensors_data_[kAccelerationId].v = acc_update; - sensors_data_[kGyroscopeId].v = gyro_update; - sensors_data_[kMagneticId].v = mgn_update; + sensors_data_[kRotationVecId].v << x, y, z; + sensors_data_[kAccelerationId].v = acc_update; + sensors_data_[kGyroscopeId].v = gyro_update; + sensors_data_[kMagneticId].v = mgn_update; - // Copy the calibrated sensor data over for uncalibrated sensor support - sensors_data_[kUncalibAccelerationId].v = acc_update; - sensors_data_[kUncalibGyroscopeId].v = gyro_update; - sensors_data_[kUncalibMagneticId].v = mgn_update; + // Copy the calibrated sensor data over for uncalibrated sensor support + sensors_data_[kUncalibAccelerationId].v = acc_update; + sensors_data_[kUncalibGyroscopeId].v = gyro_update; + sensors_data_[kUncalibMagneticId].v = mgn_update; + } + NotifySensorsChanged((1 << kRotationVecId) | (1 << kAccelerationId) | + (1 << kGyroscopeId) | (1 << kMagneticId) | + (1 << kUncalibAccelerationId) | + (1 << kUncalibGyroscopeId) | (1 << kUncalibMagneticId)); +} + +void SensorsSimulator::SetHingeAngle(float angle) { + { + std::lock_guard lock(sensors_data_mtx_); + if (sensors_data_[kHingeAngle0Id].f == angle) { + return; + } + sensors_data_[kHingeAngle0Id].f = angle; + } + NotifySensorsChanged(1 << kHingeAngle0Id); } std::string SensorsSimulator::GetSensorsData(const SensorsMask mask) { diff --git a/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_simulator.h b/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_simulator.h index e0a26620257..b92da1d7789 100644 --- a/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_simulator.h +++ b/base/cvd/cuttlefish/host/commands/sensors_simulator/sensors_simulator.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -37,8 +38,15 @@ struct SensorsData { class SensorsSimulator { public: SensorsSimulator(bool is_auto); - // Update sensor values based on new rotation status. - void RefreshSensors(double x, double y, double z); + + using SensorsChangedCallback = std::function; + // Registers a callback invoked whenever one or more sensors in |mask| are + // updated. + void SetSensorsChangedCallback(SensorsMask mask, + SensorsChangedCallback callback); + + void SetMotion(double x, double y, double z); + void SetHingeAngle(float angle); // Return a string with serialized sensors data in ascending order of // sensor id. A bitmask is used to specify which sensors to include. @@ -49,7 +57,11 @@ class SensorsSimulator { std::string GetSensorsData(const SensorsMask mask); private: + void NotifySensorsChanged(SensorsMask changed); + std::mutex sensors_data_mtx_; + SensorsMask sensors_changed_mask_ = 0; + SensorsChangedCallback sensors_changed_callback_; SensorsData sensors_data_[kMaxSensorId + 1]; Eigen::Matrix3d current_rotation_matrix_; std::chrono::time_point diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/connection_observer.cpp b/base/cvd/cuttlefish/host/frontend/webrtc/connection_observer.cpp index c22aeae1939..f979fc9dfcb 100644 --- a/base/cvd/cuttlefish/host/frontend/webrtc/connection_observer.cpp +++ b/base/cvd/cuttlefish/host/frontend/webrtc/connection_observer.cpp @@ -178,9 +178,11 @@ class ConnectionObserverImpl : public webrtc_streaming::ConnectionObserver { CF_EXPECT(OnSwitchEvent(SW_LID, !lid_open)); return {}; } - void OnHingeAngleChange(int /*hinge_angle*/) override { - // TODO(b/181157794) Propagate hinge angle sensor data using a custom - // Sensor HAL. + void OnHingeAngleChange(int hinge_angle) override { + auto result = sensors_handler_.SetHingeAngle(hinge_angle); + if (!result.ok()) { + LOG(ERROR) << "Failed to set hinge angle: " << result.error(); + } } Result OnPowerButton(bool button_down) override { CF_EXPECT(OnKeyboardEvent(KEY_POWER, button_down)); @@ -264,7 +266,10 @@ class ConnectionObserverImpl : public webrtc_streaming::ConnectionObserver { << "Y rotation value must be a double"; CHECK(absl::SimpleAtod(xyz.at(2), &z)) << "Z rotation value must be a double"; - sensors_handler_.HandleMessage(x, y, z); + auto result = sensors_handler_.SetMotion(x, y, z); + if (!result.ok()) { + LOG(ERROR) << "Failed to set motion: " << result.error(); + } } void OnLightsChannelOpen( diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/html_client/js/app.js b/base/cvd/cuttlefish/host/frontend/webrtc/html_client/js/app.js index 27a7d9399e8..07f1e95856e 100644 --- a/base/cvd/cuttlefish/host/frontend/webrtc/html_client/js/app.js +++ b/base/cvd/cuttlefish/host/frontend/webrtc/html_client/js/app.js @@ -352,18 +352,11 @@ class DeviceControlApp { 'control-panel-custom-buttons'); element.dataset.adb = true; } else if (button.device_states) { - // This button corresponds to variable hardware device state(s). let element = createControlPanelButton( button.title, button.icon_name, this.#getCustomDeviceStateButtonCb(button.device_states), 'control-panel-custom-buttons'); - for (const device_state of button.device_states) { - // hinge_angle is currently injected via an adb shell command that - // triggers a guest binary. - if ('hinge_angle_value' in device_state) { - element.dataset.adb = true; - } - } + element.dataset.adb = true; } else { // This button's command is handled by custom action server. createControlPanelButton( @@ -754,11 +747,6 @@ class DeviceControlApp { let hingeAngle = null; if ('hinge_angle_value' in states[index]) { hingeAngle = states[index].hinge_angle_value; - // TODO(b/181157794): Use a custom Sensor HAL for hinge_angle - // injection instead of this guest binary. - adbShell( - '/vendor/bin/cuttlefish_sensor_injection hinge_angle ' + - states[index].hinge_angle_value); } // Update the Device Details view. this.#updateDeviceStateDetails(lidSwitchOpen, hingeAngle); diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/sensors_handler.cpp b/base/cvd/cuttlefish/host/frontend/webrtc/sensors_handler.cpp index b02822c2650..6ccf2806a28 100644 --- a/base/cvd/cuttlefish/host/frontend/webrtc/sensors_handler.cpp +++ b/base/cvd/cuttlefish/host/frontend/webrtc/sensors_handler.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "absl/log/log.h" @@ -36,44 +37,42 @@ static constexpr sensors::SensorsMask kUiSupportedSensors = } // namespace SensorsHandler::SensorsHandler(SharedFD sensors_fd) - : channel_(transport::SharedFdChannel(sensors_fd, sensors_fd)) { - auto refresh_result = RefreshSensors(0, 0, 0); - if (!refresh_result.ok()) { - LOG(ERROR) << "Failed to refresh sensors: " << refresh_result.error(); - } -} + : channel_(transport::SharedFdChannel(sensors_fd, sensors_fd)) {} SensorsHandler::~SensorsHandler() {} -Result SensorsHandler::RefreshSensors(const double x, const double y, - const double z) { - std::stringstream ss; - ss << x << sensors::INNER_DELIM << y << sensors::INNER_DELIM << z; - auto msg = ss.str(); - auto size = msg.size(); - auto cmd = sensors::kUpdateRotationVec; +Result SensorsHandler::SendCommand(uint32_t cmd, + std::string_view payload) { + auto size = payload.size(); auto request = CF_EXPECT(transport::CreateMessage(cmd, size), "Failed to allocate message for cmd: " << cmd << " with size: " << size << " bytes. "); - memcpy(request->payload, msg.data(), size); + memcpy(request->payload, payload.data(), size); CF_EXPECT(channel_.SendRequest(*request), "Can't send request for cmd: " << cmd); return {}; } +Result SensorsHandler::SetMotion(const double x, const double y, + const double z) { + std::stringstream ss; + ss << x << sensors::INNER_DELIM << y << sensors::INNER_DELIM << z; + CF_EXPECT(SendCommand(sensors::kUpdateRotationVec, ss.str())); + UpdateSensorsUi(); + return {}; +} + +Result SensorsHandler::SetHingeAngle(const double angle) { + CF_EXPECT(SendCommand(sensors::kUpdateHingeAngle, std::to_string(angle))); + return {}; +} + Result SensorsHandler::GetSensorsData() { - auto msg = std::to_string(kUiSupportedSensors); - auto size = msg.size(); - auto cmd = sensors::kGetSensorsData; - auto request = CF_EXPECT(transport::CreateMessage(cmd, size), - "Failed to allocate message for cmd: " - << cmd << " with size: " << size << " bytes. "); - memcpy(request->payload, msg.data(), size); - CF_EXPECT(channel_.SendRequest(*request), - "Can't send request for cmd: " << cmd); + CF_EXPECT(SendCommand(sensors::kGetSensorsData, + std::to_string(kUiSupportedSensors))); auto response = CF_EXPECT(channel_.ReceiveMessage(), "Couldn't receive message."); - cmd = response->command; + auto cmd = response->command; auto is_response = response->is_response; CF_EXPECT((cmd == sensors::kGetSensorsData) && is_response, "Unexpected cmd: " << cmd << ", response: " << is_response); @@ -81,16 +80,6 @@ Result SensorsHandler::GetSensorsData() { response->payload_size); } -// Get new sensor values and send them to client. -void SensorsHandler::HandleMessage(const double x, const double y, const double z) { - auto refresh_result = RefreshSensors(x, y, z); - if (!refresh_result.ok()) { - LOG(ERROR) << "Failed to refresh sensors: " << refresh_result.error(); - return; - } - UpdateSensorsUi(); -} - int SensorsHandler::Subscribe(std::function send_to_client) { int subscriber_id = ++last_client_channel_id_; { diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/sensors_handler.h b/base/cvd/cuttlefish/host/frontend/webrtc/sensors_handler.h index 96b8985b0db..34facf29897 100644 --- a/base/cvd/cuttlefish/host/frontend/webrtc/sensors_handler.h +++ b/base/cvd/cuttlefish/host/frontend/webrtc/sensors_handler.h @@ -18,6 +18,7 @@ #include #include +#include #include #include "cuttlefish/common/libs/transport/channel_sharedfd.h" @@ -30,12 +31,14 @@ class SensorsHandler { explicit SensorsHandler(SharedFD sensors_fd); ~SensorsHandler(); - void HandleMessage(double x, double y, double z); + Result SetMotion(double x, double y, double z); + Result SetHingeAngle(double angle); + int Subscribe(std::function send_to_client); void UnSubscribe(int subscriber_id); private: - Result RefreshSensors(double x, double y, double z); + Result SendCommand(uint32_t cmd, std::string_view payload); Result GetSensorsData(); void UpdateSensorsUi();