1 // Copyright 2008 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <cstdint>
8 #include <map>
9 #include <string>
10 
11 #include "Common/CommonTypes.h"
12 #include "Core/HW/WiimoteCommon/WiimoteHid.h"
13 #include "Core/IOS/USB/Bluetooth/hci.h"
14 
15 class PointerWrap;
16 
17 namespace IOS::HLE
18 {
19 namespace Device
20 {
21 class BluetoothEmu;
22 }
23 
24 class WiimoteDevice
25 {
26 public:
27   using ClassType = std::array<u8, HCI_CLASS_SIZE>;
28   using FeaturesType = std::array<u8, HCI_FEATURES_SIZE>;
29   using LinkKeyType = std::array<u8, HCI_KEY_SIZE>;
30 
31   WiimoteDevice(Device::BluetoothEmu* host, int number, bdaddr_t bd);
32   ~WiimoteDevice();
33 
34   WiimoteDevice(const WiimoteDevice&) = delete;
35   WiimoteDevice& operator=(const WiimoteDevice&) = delete;
36   WiimoteDevice(WiimoteDevice&&) = delete;
37   WiimoteDevice& operator=(WiimoteDevice&&) = delete;
38 
39   void Reset();
40 
41   // Called every BluetoothEmu::Update.
42   void Update();
43 
44   // Called every ~200hz.
45   void UpdateInput();
46 
47   void DoState(PointerWrap& p);
48 
49   bool IsInquiryScanEnabled() const;
50   bool IsPageScanEnabled() const;
51 
52   u32 GetNumber() const;
53 
54   bool IsSourceValid() const;
55   bool IsConnected() const;
56 
57   // User-initiated. Produces UI messages.
58   void Activate(bool ready);
59 
60   // From CPU
61   void ExecuteL2capCmd(u8* ptr, u32 size);
62   // From Wiimote
63   void InterruptDataInputCallback(u8 hid_type, const u8* data, u32 size);
64 
65   bool EventConnectionAccept();
66   bool EventConnectionRequest();
67   void EventDisconnect(u8 reason);
68 
69   // nullptr may be passed to disable the remote.
70   void SetSource(WiimoteCommon::HIDWiimote*);
71 
GetBD()72   const bdaddr_t& GetBD() const { return m_bd; }
GetName()73   const char* GetName() const { return m_name.c_str(); }
GetLMPVersion()74   u8 GetLMPVersion() const { return m_lmp_version; }
GetLMPSubVersion()75   u16 GetLMPSubVersion() const { return m_lmp_subversion; }
76   // Broadcom Corporation
GetManufactorID()77   u16 GetManufactorID() const { return 0x000F; }
GetClass()78   const ClassType& GetClass() const { return m_class; }
GetFeatures()79   const FeaturesType& GetFeatures() const { return m_features; }
GetLinkKey()80   const LinkKeyType& GetLinkKey() const { return m_link_key; }
81 
82 private:
83   enum class BasebandState
84   {
85     Inactive,
86     RequestConnection,
87     Complete,
88   };
89 
90   enum class HIDState
91   {
92     Inactive,
93     Linking,
94   };
95 
96   struct SChannel
97   {
98     enum class State
99     {
100       Inactive,
101       ConfigurationPending,
102       Complete,
103     };
104 
105     SChannel();
106 
107     bool IsAccepted() const;
108     bool IsRemoteConfigured() const;
109     bool IsComplete() const;
110 
111     State state = State::Inactive;
112     u16 psm;
113     u16 remote_cid;
114     u16 remote_mtu = 0;
115   };
116 
117   using ChannelMap = std::map<u16, SChannel>;
118 
119   Device::BluetoothEmu* m_host;
120   WiimoteCommon::HIDWiimote* m_hid_source = nullptr;
121 
122   // State to save:
123   BasebandState m_baseband_state = BasebandState::Inactive;
124   HIDState m_hid_state = HIDState::Inactive;
125   bdaddr_t m_bd;
126   ClassType m_class;
127   FeaturesType m_features;
128   u8 m_lmp_version;
129   u16 m_lmp_subversion;
130   LinkKeyType m_link_key;
131   std::string m_name;
132   ChannelMap m_channels;
133   u8 m_connection_request_counter = 0;
134 
135   void SetBasebandState(BasebandState);
136 
137   const SChannel* FindChannelWithPSM(u16 psm) const;
138   SChannel* FindChannelWithPSM(u16 psm);
139 
140   bool LinkChannel(u16 psm);
141   u16 GenerateChannelID() const;
142 
DoesChannelExist(u16 scid)143   bool DoesChannelExist(u16 scid) const { return m_channels.count(scid) != 0; }
144   void SendCommandToACL(u8 ident, u8 code, u8 command_length, u8* command_data);
145 
146   void SignalChannel(u8* data, u32 size);
147 
148   void SendConnectionRequest(u16 psm);
149   void SendConfigurationRequest(u16 cid, u16 mtu, u16 flush_time_out);
150 
151   void ReceiveConnectionReq(u8 ident, u8* data, u32 size);
152   void ReceiveConnectionResponse(u8 ident, u8* data, u32 size);
153   void ReceiveDisconnectionReq(u8 ident, u8* data, u32 size);
154   void ReceiveConfigurationReq(u8 ident, u8* data, u32 size);
155   void ReceiveConfigurationResponse(u8 ident, u8* data, u32 size);
156 
157   void HandleSDP(u16 cid, u8* data, u32 size);
158   void SDPSendServiceSearchResponse(u16 cid, u16 transaction_id, u8* service_search_pattern,
159                                     u16 maximum_service_record_count);
160 
161   void SDPSendServiceAttributeResponse(u16 cid, u16 transaction_id, u32 service_handle,
162                                        u16 start_attr_id, u16 end_attr_id,
163                                        u16 maximum_attribute_byte_count, u8* continuation_state);
164 };
165 }  // namespace IOS::HLE
166