From c795207fb2dcbeaadd09b3c7316832fc27adac91 Mon Sep 17 00:00:00 2001
From: Chloe Marcec <dmarcecguzman@gmail.com>
Date: Thu, 21 Jan 2021 00:46:03 +1100
Subject: [PATCH] lbl: Implement most of lbl

Pretty basic service, only thing left to do is handle setting applying once set:sys is implemented
---
 src/core/hle/service/lbl/lbl.cpp | 283 ++++++++++++++++++++++++++++---
 1 file changed, 261 insertions(+), 22 deletions(-)

diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index 6ad3a28779..f4490f3d9f 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -20,30 +20,30 @@ public:
         static const FunctionInfo functions[] = {
             {0, nullptr, "SaveCurrentSetting"},
             {1, nullptr, "LoadCurrentSetting"},
-            {2, nullptr, "SetCurrentBrightnessSetting"},
-            {3, nullptr, "GetCurrentBrightnessSetting"},
+            {2, &LBL::SetCurrentBrightnessSetting, "SetCurrentBrightnessSetting"},
+            {3, &LBL::GetCurrentBrightnessSetting, "GetCurrentBrightnessSetting"},
             {4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"},
             {5, nullptr, "GetBrightnessSettingAppliedToBacklight"},
-            {6, nullptr, "SwitchBacklightOn"},
-            {7, nullptr, "SwitchBacklightOff"},
-            {8, nullptr, "GetBacklightSwitchStatus"},
-            {9, nullptr, "EnableDimming"},
-            {10, nullptr, "DisableDimming"},
-            {11, nullptr, "IsDimmingEnabled"},
-            {12, nullptr, "EnableAutoBrightnessControl"},
-            {13, nullptr, "DisableAutoBrightnessControl"},
-            {14, nullptr, "IsAutoBrightnessControlEnabled"},
-            {15, nullptr, "SetAmbientLightSensorValue"},
-            {16, nullptr, "GetAmbientLightSensorValue"},
-            {17, nullptr, "SetBrightnessReflectionDelayLevel"},
-            {18, nullptr, "GetBrightnessReflectionDelayLevel"},
-            {19, nullptr, "SetCurrentBrightnessMapping"},
-            {20, nullptr, "GetCurrentBrightnessMapping"},
-            {21, nullptr, "SetCurrentAmbientLightSensorMapping"},
-            {22, nullptr, "GetCurrentAmbientLightSensorMapping"},
-            {23, nullptr, "IsAmbientLightSensorAvailable"},
-            {24, nullptr, "SetCurrentBrightnessSettingForVrMode"},
-            {25, nullptr, "GetCurrentBrightnessSettingForVrMode"},
+            {6, &LBL::SwitchBacklightOn, "SwitchBacklightOn"},
+            {7, &LBL::SwitchBacklightOff, "SwitchBacklightOff"},
+            {8, &LBL::GetBacklightSwitchStatus, "GetBacklightSwitchStatus"},
+            {9, &LBL::EnableDimming, "EnableDimming"},
+            {10, &LBL::DisableDimming, "DisableDimming"},
+            {11, &LBL::IsDimmingEnabled, "IsDimmingEnabled"},
+            {12, &LBL::EnableAutoBrightnessControl, "EnableAutoBrightnessControl"},
+            {13, &LBL::DisableAutoBrightnessControl, "DisableAutoBrightnessControl"},
+            {14, &LBL::IsAutoBrightnessControlEnabled, "IsAutoBrightnessControlEnabled"},
+            {15, &LBL::SetAmbientLightSensorValue, "SetAmbientLightSensorValue"},
+            {16, &LBL::GetAmbientLightSensorValue, "GetAmbientLightSensorValue"},
+            {17, &LBL::SetBrightnessReflectionDelayLevel, "SetBrightnessReflectionDelayLevel"},
+            {18, &LBL::GetBrightnessReflectionDelayLevel, "GetBrightnessReflectionDelayLevel"},
+            {19, &LBL::SetCurrentBrightnessMapping, "SetCurrentBrightnessMapping"},
+            {20, &LBL::GetCurrentBrightnessMapping, "GetCurrentBrightnessMapping"},
+            {21, &LBL::SetCurrentAmbientLightSensorMapping, "SetCurrentAmbientLightSensorMapping"},
+            {22, &LBL::GetCurrentAmbientLightSensorMapping, "GetCurrentAmbientLightSensorMapping"},
+            {23, &LBL::IsAmbientLightSensorAvailable, "IsAmbientLightSensorAvailable"},
+            {24, &LBL::SetCurrentBrightnessSettingForVrMode, "SetCurrentBrightnessSettingForVrMode"},
+            {25, &LBL::GetCurrentBrightnessSettingForVrMode, "GetCurrentBrightnessSettingForVrMode"},
             {26, &LBL::EnableVrMode, "EnableVrMode"},
             {27, &LBL::DisableVrMode, "DisableVrMode"},
             {28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"},
@@ -55,6 +55,237 @@ public:
     }
 
 private:
+    enum class BacklightSwitchStatus : u32 {
+        Off = 0,
+        On = 1,
+    };
+
+    void SetCurrentBrightnessSetting(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        auto brightness = rp.Pop<float>();
+
+        if (!std::isfinite(brightness)) {
+            LOG_ERROR(Service_LBL, "Brightness is infinite!");
+            brightness = 0.0f;
+        }
+
+        LOG_DEBUG(Service_LBL, "called brightness={}", brightness);
+
+        current_brightness = brightness;
+        update_instantly = true;
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void GetCurrentBrightnessSetting(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        auto brightness = current_brightness;
+        if (!std::isfinite(brightness)) {
+            LOG_ERROR(Service_LBL, "Brightness is infinite!");
+            brightness = 0.0f;
+        }
+
+        LOG_DEBUG(Service_LBL, "called brightness={}", brightness);
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push(brightness);
+    }
+
+    void SwitchBacklightOn(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        const auto fade_time = rp.Pop<u64_le>();
+        LOG_WARNING(Service_LBL, "(STUBBED) called, fade_time={}", fade_time);
+
+        backlight_enabled = true;
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void SwitchBacklightOff(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        const auto fade_time = rp.Pop<u64_le>();
+        LOG_WARNING(Service_LBL, "(STUBBED) called, fade_time={}", fade_time);
+
+        backlight_enabled = false;
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void GetBacklightSwitchStatus(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_LBL, "called");
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        rb.PushEnum<BacklightSwitchStatus>(backlight_enabled ? BacklightSwitchStatus::On
+                                                             : BacklightSwitchStatus::Off);
+    }
+
+    void EnableDimming(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_LBL, "called");
+
+        dimming = true;
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void DisableDimming(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_LBL, "called");
+
+        dimming = false;
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void IsDimmingEnabled(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_LBL, "called");
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push(dimming);
+    }
+
+    void EnableAutoBrightnessControl(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_LBL, "called");
+        auto_brightness = true;
+        update_instantly = true;
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void DisableAutoBrightnessControl(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_LBL, "called");
+        auto_brightness = false;
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void IsAutoBrightnessControlEnabled(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_LBL, "called");
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push(auto_brightness);
+    }
+
+    void SetAmbientLightSensorValue(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        const auto light_value = rp.Pop<float>();
+
+        LOG_DEBUG(Service_LBL, "called light_value={}", light_value);
+
+        ambient_light_value = light_value;
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void GetAmbientLightSensorValue(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_LBL, "called");
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push(ambient_light_value);
+    }
+
+    void SetBrightnessReflectionDelayLevel(Kernel::HLERequestContext& ctx) {
+        // This is Intentional, this function does absolutely nothing
+        LOG_DEBUG(Service_LBL, "called");
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void GetBrightnessReflectionDelayLevel(Kernel::HLERequestContext& ctx) {
+        // This is intentional, the function is hard coded to return 0.0f on hardware
+        LOG_DEBUG(Service_LBL, "called");
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push(0.0f);
+    }
+
+    void SetCurrentBrightnessMapping(Kernel::HLERequestContext& ctx) {
+        // This is Intentional, this function does absolutely nothing
+        LOG_DEBUG(Service_LBL, "called");
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void GetCurrentBrightnessMapping(Kernel::HLERequestContext& ctx) {
+        // This is Intentional, this function does absolutely nothing
+        LOG_DEBUG(Service_LBL, "called");
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+        // This function is suppose to return something but it seems like it doesn't
+    }
+
+    void SetCurrentAmbientLightSensorMapping(Kernel::HLERequestContext& ctx) {
+        // This is Intentional, this function does absolutely nothing
+        LOG_DEBUG(Service_LBL, "called");
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void GetCurrentAmbientLightSensorMapping(Kernel::HLERequestContext& ctx) {
+        // This is Intentional, this function does absolutely nothing
+        LOG_DEBUG(Service_LBL, "called");
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+        // This function is suppose to return something but it seems like it doesn't
+    }
+
+    void IsAmbientLightSensorAvailable(Kernel::HLERequestContext& ctx) {
+        LOG_WARNING(Service_LBL, "(STUBBED) called");
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        // TODO(ogniK): Only return true if there's no device error
+        rb.Push(true);
+    }
+
+    void SetCurrentBrightnessSettingForVrMode(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        auto brightness = rp.Pop<float>();
+
+        if (!std::isfinite(brightness)) {
+            LOG_ERROR(Service_LBL, "Brightness is infinite!");
+            brightness = 0.0f;
+        }
+
+        LOG_DEBUG(Service_LBL, "called brightness={}", brightness);
+
+        current_vr_brightness = brightness;
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void GetCurrentBrightnessSettingForVrMode(Kernel::HLERequestContext& ctx) {
+        IPC::RequestParser rp{ctx};
+        auto brightness = current_vr_brightness;
+        if (!std::isfinite(brightness)) {
+            LOG_ERROR(Service_LBL, "Brightness is infinite!");
+            brightness = 0.0f;
+        }
+
+        LOG_DEBUG(Service_LBL, "called brightness={}", brightness);
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push(brightness);
+    }
+
     void EnableVrMode(Kernel::HLERequestContext& ctx) {
         LOG_DEBUG(Service_LBL, "called");
 
@@ -82,6 +313,14 @@ private:
     }
 
     bool vr_mode_enabled = false;
+    float current_brightness = 1.0f;
+    float backlight_brightness = 1.0f;
+    float ambient_light_value = 0.0f;
+    float current_vr_brightness = 1.0f;
+    bool dimming = true;
+    bool backlight_enabled = true;
+    bool update_instantly = false;
+    bool auto_brightness = false; // TODO(ogniK): Move to system settings
 };
 
 void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {