From eb67167b7c9b9262b0c6ce7b5c99732d228a3f8d Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 30 Dec 2019 16:07:03 +0000
Subject: [PATCH] Serialize IR service

---
 TODO                                |  2 +-
 src/core/hle/service/ir/extra_hid.h | 12 +++++++
 src/core/hle/service/ir/ir_user.cpp | 51 ++++++++++++++++++++++++-----
 src/core/hle/service/ir/ir_user.h   |  9 ++++-
 4 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/TODO b/TODO
index f72330fd1..b679a5168 100644
--- a/TODO
+++ b/TODO
@@ -85,7 +85,7 @@
             ☐ Fix the global weak_ptr to gsp
         ✔ HID @done(19-12-30 14:46)
         ✔ HTTP @done(19-12-30 15:18)
-        ☐ IR
+        ✔ IR @done(19-12-30 16:06)
         ☐ LDR_RO
         ☐ MIC
         ☐ MVD
diff --git a/src/core/hle/service/ir/extra_hid.h b/src/core/hle/service/ir/extra_hid.h
index d21cb393f..7924a1e12 100644
--- a/src/core/hle/service/ir/extra_hid.h
+++ b/src/core/hle/service/ir/extra_hid.h
@@ -6,6 +6,8 @@
 
 #include <array>
 #include <atomic>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/export.hpp>
 #include "common/bit_field.h"
 #include "common/swap.h"
 #include "core/frontend/input.h"
@@ -65,6 +67,16 @@ private:
     std::unique_ptr<Input::ButtonDevice> zr;
     std::unique_ptr<Input::AnalogDevice> c_stick;
     std::atomic<bool> is_device_reload_pending;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& hid_period;
+        ar& calibration_data; // This isn't writeable for now, but might be in future
+        RequestInputDevicesReload(); // zl, zr, c_stick are loaded here
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::IR
+
+BOOST_CLASS_EXPORT_KEY(Service::IR::ExtraHID)
diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp
index d392c1983..fd6c1b905 100644
--- a/src/core/hle/service/ir/ir_user.cpp
+++ b/src/core/hle/service/ir/ir_user.cpp
@@ -15,6 +15,19 @@
 
 namespace Service::IR {
 
+template <class Archive>
+void IR_USER::serialize(Archive& ar, const unsigned int) {
+    ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    ar& conn_status_event;
+    ar& send_event;
+    ar& receive_event;
+    ar& shared_memory;
+    ar& connected_device;
+    ar& *receive_buffer.get();
+    ar& *extra_hid.get();
+}
+SERIALIZE_IMPL(IR_USER)
+
 // This is a header that will present in the ir:USER shared memory if it is initialized with
 // InitializeIrNopShared service function. Otherwise the shared memory doesn't have this header if
 // it is initialized with InitializeIrNop service function.
@@ -139,6 +152,16 @@ private:
         u32_le end_index;
         u32_le packet_count;
         u32_le unknown;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& begin_index;
+            ar& end_index;
+            ar& packet_count;
+            ar& unknown;
+        }
+        friend class boost::serialization::access;
     };
     static_assert(sizeof(BufferInfo) == 16, "BufferInfo has wrong size!");
 
@@ -179,6 +202,18 @@ private:
     u32 buffer_offset;
     u32 max_packet_count;
     u32 max_data_size;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& info;
+        ar& shared_memory;
+        ar& info_offset;
+        ar& buffer_offset;
+        ar& max_packet_count;
+        ar& max_data_size;
+    }
+    friend class boost::serialization::access;
 };
 
 /// Wraps the payload into packet and puts it to the receive buffer
@@ -270,8 +305,8 @@ void IR_USER::RequireConnection(Kernel::HLERequestContext& ctx) {
         shared_memory_ptr[offsetof(SharedMemoryHeader, connection_role)] = 2;
         shared_memory_ptr[offsetof(SharedMemoryHeader, connected)] = 1;
 
-        connected_device = extra_hid.get();
-        connected_device->OnConnect();
+        connected_device = true;
+        extra_hid->OnConnect();
         conn_status_event->Signal();
     } else {
         LOG_WARNING(Service_IR, "unknown device id {}. Won't connect.", device_id);
@@ -305,8 +340,8 @@ void IR_USER::GetSendEvent(Kernel::HLERequestContext& ctx) {
 
 void IR_USER::Disconnect(Kernel::HLERequestContext& ctx) {
     if (connected_device) {
-        connected_device->OnDisconnect();
-        connected_device = nullptr;
+        extra_hid->OnDisconnect();
+        connected_device = false;
         conn_status_event->Signal();
     }
 
@@ -331,8 +366,8 @@ void IR_USER::GetConnectionStatusEvent(Kernel::HLERequestContext& ctx) {
 
 void IR_USER::FinalizeIrNop(Kernel::HLERequestContext& ctx) {
     if (connected_device) {
-        connected_device->OnDisconnect();
-        connected_device = nullptr;
+        extra_hid->OnDisconnect();
+        connected_device = false;
     }
 
     shared_memory = nullptr;
@@ -352,7 +387,7 @@ void IR_USER::SendIrNop(Kernel::HLERequestContext& ctx) {
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
     if (connected_device) {
-        connected_device->OnReceive(buffer);
+        extra_hid->OnReceive(buffer);
         send_event->Signal();
         rb.Push(RESULT_SUCCESS);
     } else {
@@ -424,7 +459,7 @@ IR_USER::IR_USER(Core::System& system) : ServiceFramework("ir:USER", 1) {
 
 IR_USER::~IR_USER() {
     if (connected_device) {
-        connected_device->OnDisconnect();
+        extra_hid->OnDisconnect();
     }
 }
 
diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h
index 54a4f3e08..75bbeb779 100644
--- a/src/core/hle/service/ir/ir_user.h
+++ b/src/core/hle/service/ir/ir_user.h
@@ -7,6 +7,7 @@
 #include <functional>
 #include <memory>
 #include <vector>
+#include <boost/serialization/shared_ptr.hpp>
 #include "core/hle/service/service.h"
 
 namespace Kernel {
@@ -45,6 +46,7 @@ protected:
     void Send(const std::vector<u8>& data);
 
 private:
+    // NOTE: This value is *not* serialized because it's always passed in the constructor
     const SendFunc send_func;
 };
 
@@ -164,9 +166,14 @@ private:
 
     std::shared_ptr<Kernel::Event> conn_status_event, send_event, receive_event;
     std::shared_ptr<Kernel::SharedMemory> shared_memory;
-    IRDevice* connected_device{nullptr};
+    bool connected_device;
     std::unique_ptr<BufferManager> receive_buffer;
     std::unique_ptr<ExtraHID> extra_hid;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::IR