Skip to content

Commit 05f4ece

Browse files
committed
procon pybind.
1 parent 84db49f commit 05f4ece

File tree

4 files changed

+316
-2
lines changed

4 files changed

+316
-2
lines changed
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
/* Pybind Switch Controller
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#include <mutex>
8+
#include <condition_variable>
9+
#include "CommonFramework/Logging/Logger.h"
10+
#include "Controllers/ControllerConnection.h"
11+
#include "Controllers/SerialPABotBase/SerialPABotBase_Descriptor.h"
12+
#include "NintendoSwitch/Controllers/Procon/NintendoSwitch_ProController.h"
13+
#include "PybindSwitchController.h"
14+
15+
namespace PokemonAutomation{
16+
namespace NintendoSwitch{
17+
18+
19+
20+
class PybindSwitchProControllerInternal final : public ControllerConnection::StatusListener{
21+
public:
22+
PybindSwitchProControllerInternal(const std::string& name)
23+
: m_logger(global_logger_raw(), "[Pybind]")
24+
, m_descriptor(name)
25+
, m_connection(m_descriptor.open_connection(m_logger, false))
26+
{
27+
m_connection->add_status_listener(*this);
28+
}
29+
~PybindSwitchProControllerInternal(){
30+
m_connection->remove_status_listener(*this);
31+
}
32+
33+
void wait_for_ready(){
34+
std::unique_lock<std::mutex> lg(m_wait_lock);
35+
m_cv.wait(lg, [this]{
36+
return m_procon.load(std::memory_order_acquire) && m_controller->is_ready();
37+
});
38+
}
39+
40+
virtual void post_connection_ready(ControllerConnection& connection) override{
41+
m_controller = m_descriptor.make_controller(
42+
m_logger,
43+
connection,
44+
connection.current_controller(),
45+
ControllerResetMode::DO_NOT_RESET
46+
);
47+
ProController* procon = dynamic_cast<ProController*>(m_controller.get());
48+
if (procon == nullptr){
49+
m_error = "Incompatible controller type.";
50+
return;
51+
}
52+
m_procon.store(procon, std::memory_order_release);
53+
54+
{
55+
std::unique_lock<std::mutex> lg(m_wait_lock);
56+
}
57+
m_cv.notify_all();
58+
}
59+
virtual void status_text_changed(
60+
ControllerConnection& connection, const std::string& text
61+
) override{
62+
WriteSpinLock lg(m_lock);
63+
m_status = text;
64+
}
65+
virtual void on_error(
66+
ControllerConnection& connection, const std::string& text
67+
) override{
68+
WriteSpinLock lg(m_lock);
69+
m_error = text;
70+
}
71+
72+
ProController* controller(){
73+
return m_procon.load(std::memory_order_acquire);
74+
}
75+
76+
77+
public:
78+
TaggedLogger m_logger;
79+
SerialPABotBase::SerialPABotBase_Descriptor m_descriptor;
80+
std::unique_ptr<ControllerConnection> m_connection;
81+
std::unique_ptr<AbstractController> m_controller;
82+
std::atomic<ProController*> m_procon;
83+
84+
mutable SpinLock m_lock;
85+
std::string m_status;
86+
std::string m_error;
87+
88+
std::mutex m_wait_lock;
89+
std::condition_variable m_cv;
90+
};
91+
92+
93+
94+
95+
PybindSwitchProController::PybindSwitchProController(const std::string& port_name){
96+
PybindSwitchProControllerInternal* internal = new PybindSwitchProControllerInternal(port_name);
97+
m_internals = internal;
98+
internal->wait_for_ready();
99+
}
100+
PybindSwitchProController::~PybindSwitchProController(){
101+
delete (PybindSwitchProControllerInternal*)m_internals;
102+
}
103+
104+
bool PybindSwitchProController::is_ready() const{
105+
PybindSwitchProControllerInternal* internal = (PybindSwitchProControllerInternal*)m_internals;
106+
ProController* controller = internal->controller();
107+
if (controller == nullptr){
108+
return false;
109+
}
110+
return controller->is_ready();
111+
}
112+
std::string PybindSwitchProController::current_status() const{
113+
PybindSwitchProControllerInternal* internal = (PybindSwitchProControllerInternal*)m_internals;
114+
return internal->m_connection->status_text();
115+
}
116+
117+
118+
void PybindSwitchProController::wait_for_all_requests(){
119+
PybindSwitchProControllerInternal* internal = (PybindSwitchProControllerInternal*)m_internals;
120+
ProController* controller = internal->controller();
121+
if (controller == nullptr){
122+
internal->m_logger.log("Controller is not ready.", COLOR_RED);
123+
return;
124+
}
125+
controller->wait_for_all(nullptr);
126+
}
127+
void PybindSwitchProController::wait(uint64_t duration){
128+
PybindSwitchProControllerInternal* internal = (PybindSwitchProControllerInternal*)m_internals;
129+
ProController* controller = internal->controller();
130+
if (controller == nullptr){
131+
internal->m_logger.log("Controller is not ready.", COLOR_RED);
132+
return;
133+
}
134+
controller->issue_nop(nullptr, Milliseconds(duration));
135+
}
136+
void PybindSwitchProController::push_button(uint64_t delay, uint64_t hold, uint64_t release, uint32_t bitfield){
137+
PybindSwitchProControllerInternal* internal = (PybindSwitchProControllerInternal*)m_internals;
138+
ProController* controller = internal->controller();
139+
if (controller == nullptr){
140+
internal->m_logger.log("Controller is not ready.", COLOR_RED);
141+
return;
142+
}
143+
controller->issue_buttons(
144+
nullptr,
145+
Milliseconds(delay),
146+
Milliseconds(hold),
147+
Milliseconds(release),
148+
(Button)bitfield
149+
);
150+
}
151+
void PybindSwitchProController::push_dpad(uint64_t delay, uint64_t hold, uint64_t release, uint8_t position){
152+
PybindSwitchProControllerInternal* internal = (PybindSwitchProControllerInternal*)m_internals;
153+
ProController* controller = internal->controller();
154+
if (controller == nullptr){
155+
internal->m_logger.log("Controller is not ready.", COLOR_RED);
156+
return;
157+
}
158+
controller->issue_dpad(
159+
nullptr,
160+
Milliseconds(delay),
161+
Milliseconds(hold),
162+
Milliseconds(release),
163+
(DpadPosition)position
164+
);
165+
}
166+
void PybindSwitchProController::push_left_joystick(uint64_t delay, uint64_t hold, uint64_t release, double x, double y){
167+
PybindSwitchProControllerInternal* internal = (PybindSwitchProControllerInternal*)m_internals;
168+
ProController* controller = internal->controller();
169+
if (controller == nullptr){
170+
internal->m_logger.log("Controller is not ready.", COLOR_RED);
171+
return;
172+
}
173+
controller->issue_left_joystick(
174+
nullptr,
175+
Milliseconds(delay),
176+
Milliseconds(hold),
177+
Milliseconds(release),
178+
{x, y}
179+
);
180+
}
181+
void PybindSwitchProController::push_right_joystick(uint64_t delay, uint64_t hold, uint64_t release, double x, double y){
182+
PybindSwitchProControllerInternal* internal = (PybindSwitchProControllerInternal*)m_internals;
183+
ProController* controller = internal->controller();
184+
if (controller == nullptr){
185+
internal->m_logger.log("Controller is not ready.", COLOR_RED);
186+
return;
187+
}
188+
controller->issue_right_joystick(
189+
nullptr,
190+
Milliseconds(delay),
191+
Milliseconds(hold),
192+
Milliseconds(release),
193+
{x, y}
194+
);
195+
}
196+
void PybindSwitchProController::controller_state(
197+
uint64_t duration,
198+
uint32_t button_bitfield,
199+
uint8_t dpad_position,
200+
double left_x, double left_y,
201+
double right_x, double right_y
202+
){
203+
PybindSwitchProControllerInternal* internal = (PybindSwitchProControllerInternal*)m_internals;
204+
ProController* controller = internal->controller();
205+
if (controller == nullptr){
206+
internal->m_logger.log("Controller is not ready.", COLOR_RED);
207+
return;
208+
}
209+
controller->issue_full_controller_state(
210+
nullptr,
211+
true,
212+
Milliseconds(duration),
213+
(Button)button_bitfield,
214+
(DpadPosition)dpad_position,
215+
{left_x, left_y},
216+
{right_x, right_y}
217+
);
218+
}
219+
220+
221+
222+
223+
224+
225+
226+
227+
228+
229+
}
230+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* Pybind Switch Controller
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#ifndef PokemonAutomation_Integrations_PybindSwitchController_H
8+
#define PokemonAutomation_Integrations_PybindSwitchController_H
9+
10+
#include <stdint.h>
11+
#include <string>
12+
13+
namespace PokemonAutomation{
14+
namespace NintendoSwitch{
15+
16+
17+
18+
class PybindSwitchProController{
19+
PybindSwitchProController(const PybindSwitchProController&) = delete;
20+
void operator=(const PybindSwitchProController&) = delete;
21+
22+
public:
23+
PybindSwitchProController(const std::string& port_name);
24+
~PybindSwitchProController();
25+
26+
bool is_ready() const;
27+
std::string current_status() const;
28+
29+
void wait_for_all_requests();
30+
31+
// All times are in milliseconds.
32+
void wait(uint64_t duration);
33+
void push_button(uint64_t delay, uint64_t hold, uint64_t release, uint32_t bitfield);
34+
void push_dpad(uint64_t delay, uint64_t hold, uint64_t release, uint8_t position);
35+
void push_left_joystick(uint64_t delay, uint64_t hold, uint64_t release, double x, double y);
36+
void push_right_joystick(uint64_t delay, uint64_t hold, uint64_t release, double x, double y);
37+
38+
void controller_state(
39+
uint64_t duration,
40+
uint32_t button_bitfield,
41+
uint8_t dpad_position,
42+
double left_x, double left_y,
43+
double right_x, double right_y
44+
);
45+
46+
private:
47+
void* m_internals;
48+
};
49+
50+
51+
52+
}
53+
}
54+
#endif

SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@
160160
#include "Common/Cpp/Options/CheckboxDropdownOption.h"
161161
#include "Common/Cpp/Options/CheckboxDropdownOption.tpp"
162162

163-
163+
#include "Integrations/PybindSwitchController.h"
164164

165165

166166
#include <QPixmap>
@@ -171,12 +171,27 @@
171171
using std::cout;
172172
using std::endl;
173173

174-
175174
using namespace PokemonAutomation::Kernels;
176175
using namespace PokemonAutomation::Kernels::Waterfill;
177176

178177

179178

179+
180+
namespace PokemonAutomation{
181+
182+
183+
184+
185+
186+
187+
188+
189+
190+
191+
}
192+
193+
194+
180195
namespace PokemonAutomation{
181196
namespace NintendoSwitch{
182197

@@ -292,6 +307,13 @@ class TealDialogMatcher : public ImageMatch::WaterfillTemplateMatcher{
292307

293308

294309

310+
311+
312+
313+
314+
315+
316+
295317
void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& scope){
296318
using namespace Kernels;
297319
using namespace Kernels::Waterfill;
@@ -314,6 +336,12 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope&
314336
VideoOverlaySet overlays(overlay);
315337

316338

339+
{
340+
PybindSwitchProController controller("COM12");
341+
controller.push_button(1000, 200, 800, BUTTON_B);
342+
controller.wait_for_all_requests();
343+
}
344+
317345

318346

319347

SerialPrograms/cmake/SourceFiles.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,8 @@ file(GLOB LIBRARY_SOURCES
744744
Source/Integrations/IntegrationsAPI.h
745745
Source/Integrations/ProgramTracker.cpp
746746
Source/Integrations/ProgramTracker.h
747+
Source/Integrations/PybindSwitchController.cpp
748+
Source/Integrations/PybindSwitchController.h
747749
Source/Kernels/AbsFFT/Kernels_AbsFFT.cpp
748750
Source/Kernels/AbsFFT/Kernels_AbsFFT.h
749751
Source/Kernels/AbsFFT/Kernels_AbsFFT_Arch.h

0 commit comments

Comments
 (0)