1 // Copyright 2016 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <atomic>
8 #include <memory>
9 #include <boost/serialization/binary_object.hpp>
10 #include "common/common_types.h"
11 #include "core/hle/service/service.h"
12 
13 namespace Core {
14 class System;
15 }
16 
17 namespace Kernel {
18 class Event;
19 } // namespace Kernel
20 
21 namespace Service::NFC {
22 
23 namespace ErrCodes {
24 enum {
25     CommandInvalidForState = 512,
26 };
27 } // namespace ErrCodes
28 
29 // TODO(FearlessTobi): Add more members to this struct
30 struct AmiiboData {
31     std::array<u8, 7> uuid;
32     INSERT_PADDING_BYTES(0x4D);
33     u16_le char_id;
34     u8 char_variant;
35     u8 figure_type;
36     u16_be model_number;
37     u8 series;
38     INSERT_PADDING_BYTES(0x1C1);
39 
40 private:
41     template <class Archive>
serializeAmiiboData42     void serialize(Archive& ar, const unsigned int) {
43         ar& boost::serialization::make_binary_object(this, sizeof(AmiiboData));
44     }
45     friend class boost::serialization::access;
46 };
47 static_assert(sizeof(AmiiboData) == 0x21C, "AmiiboData is an invalid size");
48 
49 enum class TagState : u8 {
50     NotInitialized = 0,
51     NotScanning = 1,
52     Scanning = 2,
53     TagInRange = 3,
54     TagOutOfRange = 4,
55     TagDataLoaded = 5,
56     Unknown6 = 6,
57 };
58 
59 enum class CommunicationStatus : u8 {
60     AttemptInitialize = 1,
61     NfcInitialized = 2,
62 };
63 
64 class Module final {
65 public:
66     explicit Module(Core::System& system);
67     ~Module();
68 
69     class Interface : public ServiceFramework<Interface> {
70     public:
71         Interface(std::shared_ptr<Module> nfc, const char* name, u32 max_session);
72         ~Interface();
73 
74         std::shared_ptr<Module> GetModule() const;
75 
76         void LoadAmiibo(const AmiiboData& amiibo_data);
77 
78         void RemoveAmiibo();
79 
80     protected:
81         /**
82          * NFC::Initialize service function
83          *  Inputs:
84          *      0 : Header code [0x00010040]
85          *      1 : (u8) unknown parameter. Can be either value 0x1 or 0x2
86          *  Outputs:
87          *      1 : Result of function, 0 on success, otherwise error code
88          */
89         void Initialize(Kernel::HLERequestContext& ctx);
90 
91         /**
92          * NFC::Shutdown service function
93          *  Inputs:
94          *      0 : Header code [0x00020040]
95          *      1 : (u8) unknown parameter
96          *  Outputs:
97          *      1 : Result of function, 0 on success, otherwise error code
98          */
99         void Shutdown(Kernel::HLERequestContext& ctx);
100 
101         /**
102          * NFC::StartCommunication service function
103          *  Inputs:
104          *      0 : Header code [0x00030000]
105          *  Outputs:
106          *      1 : Result of function, 0 on success, otherwise error code
107          */
108         void StartCommunication(Kernel::HLERequestContext& ctx);
109 
110         /**
111          * NFC::StopCommunication service function
112          *  Inputs:
113          *      0 : Header code [0x00040000]
114          *  Outputs:
115          *      1 : Result of function, 0 on success, otherwise error code
116          */
117         void StopCommunication(Kernel::HLERequestContext& ctx);
118 
119         /**
120          * NFC::StartTagScanning service function
121          *  Inputs:
122          *      0 : Header code [0x00050040]
123          *      1 : (u16) unknown. This is normally 0x0
124          *  Outputs:
125          *      1 : Result of function, 0 on success, otherwise error code
126          */
127         void StartTagScanning(Kernel::HLERequestContext& ctx);
128 
129         /**
130          * NFC::StopTagScanning service function
131          *  Inputs:
132          *      0 : Header code [0x00060000]
133          *  Outputs:
134          *      1 : Result of function, 0 on success, otherwise error code
135          */
136         void StopTagScanning(Kernel::HLERequestContext& ctx);
137 
138         /**
139          * NFC::LoadAmiiboData service function
140          *  Inputs:
141          *      0 : Header code [0x00070000]
142          *  Outputs:
143          *      1 : Result of function, 0 on success, otherwise error code
144          */
145         void LoadAmiiboData(Kernel::HLERequestContext& ctx);
146 
147         /**
148          * NFC::ResetTagScanState service function
149          *  Inputs:
150          *      0 : Header code [0x00080000]
151          *  Outputs:
152          *      1 : Result of function, 0 on success, otherwise error code
153          */
154         void ResetTagScanState(Kernel::HLERequestContext& ctx);
155 
156         /**
157          * NFC::GetTagInRangeEvent service function
158          *  Inputs:
159          *      0 : Header code [0x000B0000]
160          *  Outputs:
161          *      1 : Result of function, 0 on success, otherwise error code
162          *      2 : Copy handle descriptor
163          *      3 : Event Handle
164          */
165         void GetTagInRangeEvent(Kernel::HLERequestContext& ctx);
166 
167         /**
168          * NFC::GetTagOutOfRangeEvent service function
169          *  Inputs:
170          *      0 : Header code [0x000C0000]
171          *  Outputs:
172          *      1 : Result of function, 0 on success, otherwise error code
173          *      2 : Copy handle descriptor
174          *      3 : Event Handle
175          */
176         void GetTagOutOfRangeEvent(Kernel::HLERequestContext& ctx);
177 
178         /**
179          * NFC::GetTagState service function
180          *  Inputs:
181          *      0 : Header code [0x000D0000]
182          *  Outputs:
183          *      1 : Result of function, 0 on success, otherwise error code
184          *      2 : (u8) Tag state
185          */
186         void GetTagState(Kernel::HLERequestContext& ctx);
187 
188         /**
189          * NFC::CommunicationGetStatus service function
190          *  Inputs:
191          *      0 : Header code [0x000F0000]
192          *  Outputs:
193          *      1 : Result of function, 0 on success, otherwise error code
194          *      2 : (u8) Communication state
195          */
196         void CommunicationGetStatus(Kernel::HLERequestContext& ctx);
197 
198         /**
199          * NFC::GetTagInfo service function
200          *  Inputs:
201          *      0 : Header code [0x00110000]
202          *  Outputs:
203          *      1 : Result of function, 0 on success, otherwise error code
204          *   2-12 : 0x2C-byte struct
205          */
206         void GetTagInfo(Kernel::HLERequestContext& ctx);
207 
208         /**
209          * NFC::GetAmiiboConfig service function
210          *  Inputs:
211          *      0 : Header code [0x00180000]
212          *  Outputs:
213          *      1 : Result of function, 0 on success, otherwise error code
214          *   2-17 : 0x40-byte config struct
215          */
216         void GetAmiiboConfig(Kernel::HLERequestContext& ctx);
217 
218         /**
219          * NFC::Unknown0x1A service function
220          *  Inputs:
221          *      0 : Header code [0x001A0000]
222          *  Outputs:
223          *      1 : Result of function, 0 on success, otherwise error code
224          */
225         void Unknown0x1A(Kernel::HLERequestContext& ctx);
226 
227         /**
228          * NFC::GetIdentificationBlock service function
229          *  Inputs:
230          *      0 : Header code [0x001B0000]
231          *  Outputs:
232          *      1 : Result of function, 0 on success, otherwise error code
233          *   2-31 : 0x36-byte struct
234          */
235         void GetIdentificationBlock(Kernel::HLERequestContext& ctx);
236 
237     protected:
238         std::shared_ptr<Module> nfc;
239     };
240 
241 private:
242     // Sync nfc_tag_state with amiibo_in_range and signal events on state change.
243     void SyncTagState();
244 
245     std::shared_ptr<Kernel::Event> tag_in_range_event;
246     std::shared_ptr<Kernel::Event> tag_out_of_range_event;
247     TagState nfc_tag_state = TagState::NotInitialized;
248     CommunicationStatus nfc_status = CommunicationStatus::NfcInitialized;
249 
250     AmiiboData amiibo_data{};
251     bool amiibo_in_range = false;
252 
253     template <class Archive>
254     void serialize(Archive& ar, const unsigned int);
255     friend class boost::serialization::access;
256 };
257 
258 void InstallInterfaces(Core::System& system);
259 
260 } // namespace Service::NFC
261 
262 SERVICE_CONSTRUCT(Service::NFC::Module)
263 BOOST_CLASS_EXPORT_KEY(Service::NFC::Module)
264