Added stick input and loops to macros
This commit is contained in:
parent
a4bce53d1e
commit
db4b550166
10 changed files with 384 additions and 61 deletions
67
demo.py
67
demo.py
|
|
@ -1,8 +1,7 @@
|
||||||
import time
|
import time
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
from nxbt import Nxbt
|
import nxbt
|
||||||
from nxbt import ControllerTypes
|
|
||||||
|
|
||||||
MACRO = """
|
MACRO = """
|
||||||
B 0.1s
|
B 0.1s
|
||||||
|
|
@ -13,25 +12,44 @@ B 0.1s
|
||||||
0.1s
|
0.1s
|
||||||
B 0.1s
|
B 0.1s
|
||||||
1.5s
|
1.5s
|
||||||
DPAD_LEFT 0.1s
|
|
||||||
0.1s
|
|
||||||
DPAD_LEFT 0.1s
|
|
||||||
0.1s
|
|
||||||
DPAD_LEFT 0.1s
|
|
||||||
0.1s
|
|
||||||
DPAD_LEFT 0.1s
|
|
||||||
0.1s
|
|
||||||
DPAD_LEFT 0.1s
|
|
||||||
0.1s
|
|
||||||
DPAD_RIGHT 0.075s
|
|
||||||
0.075s
|
|
||||||
DPAD_RIGHT 0.075s
|
|
||||||
0.075s
|
|
||||||
DPAD_RIGHT 0.075s
|
DPAD_RIGHT 0.075s
|
||||||
0.075s
|
0.075s
|
||||||
A 0.1s
|
A 0.1s
|
||||||
1.5s
|
1.5s
|
||||||
|
DPAD_DOWN 1.0s
|
||||||
A 0.1s
|
A 0.1s
|
||||||
|
0.25s
|
||||||
|
DPAD_DOWN 0.8s
|
||||||
|
A 0.1s
|
||||||
|
0.25s
|
||||||
|
L_STICK_PRESS 0.1s
|
||||||
|
1.0s
|
||||||
|
L_STICK@-100+000 0.75s
|
||||||
|
L_STICK@+000+100 0.75s
|
||||||
|
L_STICK@+100+000 0.75s
|
||||||
|
L_STICK@+000-100 0.75s
|
||||||
|
B 0.1s
|
||||||
|
0.25s
|
||||||
|
R_STICK_PRESS 0.1s
|
||||||
|
1.0s
|
||||||
|
R_STICK@-100+000 0.75s
|
||||||
|
R_STICK@+000+100 0.75s
|
||||||
|
R_STICK@+100+000 0.75s
|
||||||
|
R_STICK@+000-100 0.75s
|
||||||
|
B 0.1s
|
||||||
|
0.1s
|
||||||
|
B 0.1s
|
||||||
|
0.1s
|
||||||
|
B 0.1s
|
||||||
|
0.1s
|
||||||
|
B 0.1s
|
||||||
|
0.4s
|
||||||
|
DPAD_LEFT 0.1s
|
||||||
|
0.1s
|
||||||
|
A 0.1s
|
||||||
|
1.5s
|
||||||
|
A 0.1s
|
||||||
|
0.1s
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -48,25 +66,26 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# Loop over all Bluetooth adapters and create
|
# Loop over all Bluetooth adapters and create
|
||||||
# Switch Pro Controllers
|
# Switch Pro Controllers
|
||||||
nxbt = Nxbt()
|
nx = nxbt.Nxbt()
|
||||||
adapters = nxbt.get_available_adapters()
|
adapters = nx.get_available_adapters()
|
||||||
# adapters = ["/org/bluez/hci0"]
|
|
||||||
controller_idxs = []
|
controller_idxs = []
|
||||||
for i in range(0, len(adapters)):
|
for i in range(0, len(adapters)):
|
||||||
index = nxbt.create_controller(
|
index = nx.create_controller(
|
||||||
ControllerTypes.PRO_CONTROLLER,
|
nxbt.PRO_CONTROLLER,
|
||||||
adapters[i],
|
adapters[i],
|
||||||
colour_body=random_colour(),
|
colour_body=random_colour(),
|
||||||
colour_buttons=random_colour())
|
colour_buttons=random_colour())
|
||||||
controller_idxs.append(index)
|
controller_idxs.append(index)
|
||||||
|
|
||||||
# Run a macro on the last controller
|
# Run a macro on the last controller
|
||||||
nxbt.macro(controller_idxs[-1], MACRO, block=False)
|
# and don't wait for the macro to complete
|
||||||
|
nx.macro(controller_idxs[-1], MACRO, block=False)
|
||||||
|
|
||||||
# Check the state
|
# Check the state
|
||||||
while True:
|
while True:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
for key in nxbt.state.keys():
|
for key in nx.state.keys():
|
||||||
state = nxbt.state[key]
|
state = nx.state[key]
|
||||||
if not state["errors"]:
|
if not state["errors"]:
|
||||||
print(state)
|
print(state)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
from .controller import ControllerServer
|
from .controller import ControllerServer
|
||||||
from .controller import ControllerTypes
|
|
||||||
from .controller import ControllerProtocol
|
from .controller import ControllerProtocol
|
||||||
from .controller import SwitchReportParser
|
from .controller import SwitchReportParser
|
||||||
from .controller import SwitchResponses
|
from .controller import SwitchResponses
|
||||||
from .controller import Controller
|
from .controller import Controller
|
||||||
from .bluez import *
|
from .bluez import *
|
||||||
from .nxbt import Nxbt
|
from .nxbt import Nxbt
|
||||||
|
from .nxbt import JOYCON_L
|
||||||
|
from .nxbt import JOYCON_R
|
||||||
|
from .nxbt import PRO_CONTROLLER
|
||||||
|
|
|
||||||
121
nxbt/cli.py
121
nxbt/cli.py
|
|
@ -1,5 +1,124 @@
|
||||||
|
import argparse
|
||||||
|
import time
|
||||||
|
from random import randint
|
||||||
|
|
||||||
from .web import start_web_app
|
from .web import start_web_app
|
||||||
|
from .nxbt import Nxbt, PRO_CONTROLLER
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('command', default=False, choices=['start', 'demo'],
|
||||||
|
help="Specifies the Nxbt command to run")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
MACRO = """
|
||||||
|
LOOP 100
|
||||||
|
B 0.1s
|
||||||
|
0.1s
|
||||||
|
B 0.1s
|
||||||
|
0.1s
|
||||||
|
B 0.1s
|
||||||
|
0.1s
|
||||||
|
B 0.1s
|
||||||
|
1.5s
|
||||||
|
DPAD_RIGHT 0.075s
|
||||||
|
0.075s
|
||||||
|
A 0.1s
|
||||||
|
1.5s
|
||||||
|
DPAD_DOWN 1.0s
|
||||||
|
A 0.1s
|
||||||
|
0.25s
|
||||||
|
DPAD_DOWN 0.8s
|
||||||
|
A 0.1s
|
||||||
|
0.25s
|
||||||
|
L_STICK_PRESS 0.1s
|
||||||
|
1.0s
|
||||||
|
L_STICK@-100+000 0.75s
|
||||||
|
L_STICK@+000+100 0.75s
|
||||||
|
L_STICK@+100+000 0.75s
|
||||||
|
L_STICK@+000-100 0.75s
|
||||||
|
B 0.1s
|
||||||
|
0.25s
|
||||||
|
R_STICK_PRESS 0.1s
|
||||||
|
1.0s
|
||||||
|
R_STICK@-100+000 0.75s
|
||||||
|
R_STICK@+000+100 0.75s
|
||||||
|
R_STICK@+100+000 0.75s
|
||||||
|
R_STICK@+000-100 0.75s
|
||||||
|
B 0.1s
|
||||||
|
0.1s
|
||||||
|
B 0.1s
|
||||||
|
0.1s
|
||||||
|
B 0.1s
|
||||||
|
0.1s
|
||||||
|
B 0.1s
|
||||||
|
0.4s
|
||||||
|
DPAD_LEFT 0.1s
|
||||||
|
0.1s
|
||||||
|
A 0.1s
|
||||||
|
1.5s
|
||||||
|
A 0.1s
|
||||||
|
20.0s
|
||||||
|
"""
|
||||||
|
|
||||||
|
MACRO = """
|
||||||
|
B 0.1s
|
||||||
|
3.0s
|
||||||
|
A 0.1s
|
||||||
|
3.0s
|
||||||
|
20.0s
|
||||||
|
B 0.1s
|
||||||
|
LOOP 100
|
||||||
|
B 0.1s
|
||||||
|
0.1s
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def random_colour():
|
||||||
|
|
||||||
|
return [
|
||||||
|
randint(0, 255),
|
||||||
|
randint(0, 255),
|
||||||
|
randint(0, 255),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def demo():
|
||||||
|
"""Loops over all available Bluetooth adapters
|
||||||
|
and creates controllers on each. The last available adapter
|
||||||
|
is used to run a macro.
|
||||||
|
"""
|
||||||
|
|
||||||
|
nx = Nxbt()
|
||||||
|
adapters = nx.get_available_adapters()
|
||||||
|
controller_idxs = []
|
||||||
|
for i in range(0, len(adapters)):
|
||||||
|
index = nx.create_controller(
|
||||||
|
PRO_CONTROLLER,
|
||||||
|
adapters[i],
|
||||||
|
colour_body=random_colour(),
|
||||||
|
colour_buttons=random_colour())
|
||||||
|
controller_idxs.append(index)
|
||||||
|
|
||||||
|
# Run a macro on the last controller
|
||||||
|
# and don't wait for the macro to complete
|
||||||
|
nx.macro(controller_idxs[-1], MACRO, block=False)
|
||||||
|
|
||||||
|
# Check the state
|
||||||
|
while True:
|
||||||
|
time.sleep(1)
|
||||||
|
for key in nx.state.keys():
|
||||||
|
state = nx.state[key]
|
||||||
|
if not state["errors"]:
|
||||||
|
print(state)
|
||||||
|
else:
|
||||||
|
print(state["errors"])
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
start_web_app()
|
|
||||||
|
if args.command == 'start':
|
||||||
|
start_web_app()
|
||||||
|
elif args.command == 'demo':
|
||||||
|
demo()
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,34 @@ from time import perf_counter
|
||||||
|
|
||||||
class InputParser():
|
class InputParser():
|
||||||
|
|
||||||
|
# Left Stick calibration values
|
||||||
|
LEFT_STICK_CALIBRATION = {
|
||||||
|
"center_x": 2159,
|
||||||
|
"center_y": 1916,
|
||||||
|
# Zeroed Min/Max X and Y
|
||||||
|
"min_x": -1466,
|
||||||
|
"max_x": 1517,
|
||||||
|
"min_y": -1583,
|
||||||
|
"max_y": 1465,
|
||||||
|
}
|
||||||
|
# Right Stick calibration values
|
||||||
|
RIGHT_STICK_CALIBRATION = {
|
||||||
|
"center_x": 2070,
|
||||||
|
"center_y": 2013,
|
||||||
|
# Zeroed Min/Max X and Y
|
||||||
|
"min_x": -1522,
|
||||||
|
"max_x": 1414,
|
||||||
|
"min_y": -1531,
|
||||||
|
"max_y": 1510,
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, protocol):
|
def __init__(self, protocol):
|
||||||
|
|
||||||
self.protocol = protocol
|
self.protocol = protocol
|
||||||
|
|
||||||
# Buffers a list of unparsed macros
|
# Buffers a list of unparsed macros
|
||||||
self.macro_buffer = []
|
self.macro_buffer = []
|
||||||
|
|
||||||
# Keeps track of the entire current
|
# Keeps track of the entire current
|
||||||
# list of macro commands.
|
# list of macro commands.
|
||||||
self.current_macro = None
|
self.current_macro = None
|
||||||
|
|
@ -16,8 +38,10 @@ class InputParser():
|
||||||
# Keeps track of the macro commands being
|
# Keeps track of the macro commands being
|
||||||
# input over a period of time.
|
# input over a period of time.
|
||||||
self.current_macro_commands = None
|
self.current_macro_commands = None
|
||||||
|
|
||||||
# The time length of the current macro
|
# The time length of the current macro
|
||||||
self.macro_timer_length = 0
|
self.macro_timer_length = 0
|
||||||
|
|
||||||
# The start time for the current macro commands
|
# The start time for the current macro commands
|
||||||
self.macro_timer_start = 0
|
self.macro_timer_start = 0
|
||||||
|
|
||||||
|
|
@ -47,8 +71,7 @@ class InputParser():
|
||||||
if not self.current_macro and self.macro_buffer:
|
if not self.current_macro and self.macro_buffer:
|
||||||
# Preprocess command lines of current macro
|
# Preprocess command lines of current macro
|
||||||
macro = self.macro_buffer.pop(0)
|
macro = self.macro_buffer.pop(0)
|
||||||
self.current_macro = macro[0].strip("\n")
|
self.current_macro = self.parse_macro(macro[0])
|
||||||
self.current_macro = self.current_macro.split("\n")
|
|
||||||
self.current_macro_id = macro[1]
|
self.current_macro_id = macro[1]
|
||||||
|
|
||||||
# Check if we can load the next set of commands
|
# Check if we can load the next set of commands
|
||||||
|
|
@ -62,6 +85,7 @@ class InputParser():
|
||||||
self.macro_timer_length = float(timer_length)
|
self.macro_timer_length = float(timer_length)
|
||||||
self.macro_timer_start = perf_counter()
|
self.macro_timer_start = perf_counter()
|
||||||
|
|
||||||
|
print(self.current_macro_commands)
|
||||||
self.parse_macro_input(self.current_macro_commands)
|
self.parse_macro_input(self.current_macro_commands)
|
||||||
|
|
||||||
# Check if we're done inputting the current command
|
# Check if we're done inputting the current command
|
||||||
|
|
@ -78,6 +102,57 @@ class InputParser():
|
||||||
|
|
||||||
return controller_input
|
return controller_input
|
||||||
|
|
||||||
|
def parse_macro(self, macro):
|
||||||
|
|
||||||
|
parsed = macro.split("\n")
|
||||||
|
parsed = list(filter(lambda s: not s.strip() == "", parsed))
|
||||||
|
parsed = self.parse_loops(parsed)
|
||||||
|
|
||||||
|
return parsed
|
||||||
|
|
||||||
|
def parse_loops(self, macro):
|
||||||
|
parsed = []
|
||||||
|
i = 0
|
||||||
|
while i < len(macro):
|
||||||
|
line = macro[i]
|
||||||
|
if line.startswith("LOOP"):
|
||||||
|
loop_count = int(line.split(" ")[1])
|
||||||
|
loop_buffer = []
|
||||||
|
|
||||||
|
# Detect delimiter and record
|
||||||
|
if macro[i+1].startswith("\t"):
|
||||||
|
loop_delimiter = "\t"
|
||||||
|
elif macro[i+1].startswith(" "):
|
||||||
|
loop_delimiter = " "
|
||||||
|
else:
|
||||||
|
loop_delimiter = " "
|
||||||
|
|
||||||
|
# Gather looping commands
|
||||||
|
for j in range(i+1, len(macro)):
|
||||||
|
loop_line = macro[j]
|
||||||
|
if loop_line.startswith(loop_delimiter):
|
||||||
|
# Replace the first instance of the delimiter
|
||||||
|
loop_line = loop_line.replace(loop_delimiter, "", 1)
|
||||||
|
loop_buffer.append(loop_line)
|
||||||
|
# Set the new position if we either encounter the end
|
||||||
|
# of the loop or we reach the end of the macro
|
||||||
|
else:
|
||||||
|
i = j - 1
|
||||||
|
break
|
||||||
|
if j+1 >= len(macro):
|
||||||
|
i = j
|
||||||
|
|
||||||
|
# Recursively gather other loops if present
|
||||||
|
if any(s.startswith("LOOP") for s in loop_buffer):
|
||||||
|
loop_buffer = self.parse_loops(loop_buffer)
|
||||||
|
# Multiply out the loop and concatenate
|
||||||
|
parsed = parsed + (loop_buffer * loop_count)
|
||||||
|
else:
|
||||||
|
parsed.append(line)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return parsed
|
||||||
|
|
||||||
def parse_macro_input(self, macro_input):
|
def parse_macro_input(self, macro_input):
|
||||||
|
|
||||||
# Checking if this is a wait macro command
|
# Checking if this is a wait macro command
|
||||||
|
|
@ -89,6 +164,9 @@ class InputParser():
|
||||||
upper = ['0'] * 8
|
upper = ['0'] * 8
|
||||||
shared = ['0'] * 8
|
shared = ['0'] * 8
|
||||||
lower = ['0'] * 8
|
lower = ['0'] * 8
|
||||||
|
# Analog stick byte placeholders
|
||||||
|
stick_left = None
|
||||||
|
stick_right = None
|
||||||
for i in range(0, len(macro_input)-1):
|
for i in range(0, len(macro_input)-1):
|
||||||
button = macro_input[i]
|
button = macro_input[i]
|
||||||
# Upper Byte
|
# Upper Byte
|
||||||
|
|
@ -114,9 +192,9 @@ class InputParser():
|
||||||
shared[7] = '1'
|
shared[7] = '1'
|
||||||
elif button == "+":
|
elif button == "+":
|
||||||
shared[6] = '1'
|
shared[6] = '1'
|
||||||
elif button == "R_ANALOG_DOWN":
|
elif button == "R_STICK_PRESS":
|
||||||
shared[5] = '1'
|
shared[5] = '1'
|
||||||
elif button == "L_ANALOG_DOWN":
|
elif button == "L_STICK_PRESS":
|
||||||
shared[4] = '1'
|
shared[4] = '1'
|
||||||
elif button == "HOME":
|
elif button == "HOME":
|
||||||
shared[3] = '1'
|
shared[3] = '1'
|
||||||
|
|
@ -141,9 +219,84 @@ class InputParser():
|
||||||
elif button == "ZL":
|
elif button == "ZL":
|
||||||
lower[0] = '1'
|
lower[0] = '1'
|
||||||
|
|
||||||
|
# Analog Stick Positions
|
||||||
|
elif button.startswith("L_STICK@"):
|
||||||
|
stick_left = self.parse_macro_stick_position(button)
|
||||||
|
elif button.startswith("R_STICK@"):
|
||||||
|
stick_right = self.parse_macro_stick_position(button)
|
||||||
|
|
||||||
# Converting binary strings to ints
|
# Converting binary strings to ints
|
||||||
upper_byte = int("".join(upper), 2)
|
upper_byte = int("".join(upper), 2)
|
||||||
shared_byte = int("".join(shared), 2)
|
shared_byte = int("".join(shared), 2)
|
||||||
lower_byte = int("".join(lower), 2)
|
lower_byte = int("".join(lower), 2)
|
||||||
|
|
||||||
self.protocol.set_button_inputs(upper_byte, shared_byte, lower_byte)
|
self.protocol.set_button_inputs(upper_byte, shared_byte, lower_byte)
|
||||||
|
if stick_left:
|
||||||
|
self.protocol.set_left_stick_inputs(stick_left)
|
||||||
|
if stick_right:
|
||||||
|
self.protocol.set_right_stick_inputs(stick_right)
|
||||||
|
|
||||||
|
def parse_macro_stick_position(self, stick_pos):
|
||||||
|
|
||||||
|
stick_type = stick_pos.split("@")[0]
|
||||||
|
positions = stick_pos.split("@")[1]
|
||||||
|
if len(positions) < 8:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Converting macro to proper ratios
|
||||||
|
sign_x = positions[0]
|
||||||
|
ratio_x = int(positions[1:4]) / 100
|
||||||
|
if sign_x == "-":
|
||||||
|
ratio_x = ratio_x * -1
|
||||||
|
|
||||||
|
sign_y = positions[4]
|
||||||
|
ratio_y = int(positions[5:8]) / 100
|
||||||
|
if sign_y == "-":
|
||||||
|
ratio_y = ratio_y * -1
|
||||||
|
|
||||||
|
calibrated_position = self.stick_ratio_to_calibrated_position(
|
||||||
|
ratio_x, ratio_y, stick_type)
|
||||||
|
|
||||||
|
return calibrated_position
|
||||||
|
|
||||||
|
def stick_ratio_to_calibrated_position(self, ratio_x, ratio_y, stick_type):
|
||||||
|
|
||||||
|
# Using the appropriate calibration values for the stick type
|
||||||
|
if stick_type == "L_STICK":
|
||||||
|
cal = self.LEFT_STICK_CALIBRATION
|
||||||
|
else:
|
||||||
|
cal = self.RIGHT_STICK_CALIBRATION
|
||||||
|
|
||||||
|
# Converting ratios to uint16 values
|
||||||
|
if ratio_x < 0:
|
||||||
|
data_x_converted = (
|
||||||
|
abs(ratio_x) * cal["min_x"] + cal["center_x"])
|
||||||
|
else:
|
||||||
|
data_x_converted = (
|
||||||
|
abs(ratio_x) * cal["max_x"] + cal["center_x"])
|
||||||
|
data_x_converted = int(round(data_x_converted))
|
||||||
|
|
||||||
|
if ratio_y < 0:
|
||||||
|
data_y_converted = (
|
||||||
|
abs(ratio_y) * cal["min_y"] + cal["center_y"])
|
||||||
|
else:
|
||||||
|
data_y_converted = (
|
||||||
|
abs(ratio_y) * cal["max_y"] + cal["center_y"])
|
||||||
|
data_y_converted = int(round(data_y_converted))
|
||||||
|
|
||||||
|
# Converting the two X/Y uint16 values to 3 uint8 Little Endian values
|
||||||
|
# using bitshifting techniques
|
||||||
|
converted_values = [
|
||||||
|
# Get the last two hex digits
|
||||||
|
data_x_converted & 0xFF,
|
||||||
|
# Combine the last digit of the Y uint16 and the first digit
|
||||||
|
# of the X uint16
|
||||||
|
((data_y_converted & 0xF) << 4) + (data_x_converted >> 8),
|
||||||
|
# Get the first two digits of the Y uint16
|
||||||
|
data_y_converted >> 4]
|
||||||
|
|
||||||
|
return converted_values
|
||||||
|
|
||||||
|
def reassign_protocol(self, protocol):
|
||||||
|
|
||||||
|
self.protocol = protocol
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import random
|
||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
|
|
||||||
from .controller import ControllerTypes
|
from .controller import ControllerTypes
|
||||||
from .utils import replace_subarray
|
from .utils import replace_subarray, format_msg_controller
|
||||||
|
|
||||||
|
|
||||||
class SwitchResponses(Enum):
|
class SwitchResponses(Enum):
|
||||||
|
|
@ -97,19 +97,19 @@ class ControllerProtocol():
|
||||||
|
|
||||||
# Disable left stick if we have a right Joy-Con
|
# Disable left stick if we have a right Joy-Con
|
||||||
if self.controller_type == ControllerTypes.JOYCON_R:
|
if self.controller_type == ControllerTypes.JOYCON_R:
|
||||||
self.left_stick_status = [0x00] * 3
|
self.left_stick_centre = [0x00] * 3
|
||||||
else:
|
else:
|
||||||
# Center values which are also reported under
|
# Center values which are also reported under
|
||||||
# SPI Stick calibration reads
|
# SPI Stick calibration reads
|
||||||
self.left_stick_status = [0x6F, 0xC8, 0x77]
|
self.left_stick_centre = [0x6F, 0xC8, 0x77]
|
||||||
|
|
||||||
# Disable right stick if we have a left Joy-Con
|
# Disable right stick if we have a left Joy-Con
|
||||||
if self.controller_type == ControllerTypes.JOYCON_L:
|
if self.controller_type == ControllerTypes.JOYCON_L:
|
||||||
self.right_stick_status = [0x00] * 3
|
self.right_stick_centre = [0x00] * 3
|
||||||
else:
|
else:
|
||||||
# Center values which are also reported under
|
# Center values which are also reported under
|
||||||
# SPI Stick calibration reads
|
# SPI Stick calibration reads
|
||||||
self.right_stick_status = [0x16, 0xD8, 0x7D]
|
self.right_stick_centre = [0x16, 0xD8, 0x7D]
|
||||||
|
|
||||||
self.vibrator_report = random.choice(self.VIBRATOR_BYTES)
|
self.vibrator_report = random.choice(self.VIBRATOR_BYTES)
|
||||||
|
|
||||||
|
|
@ -130,6 +130,7 @@ class ControllerProtocol():
|
||||||
def get_report(self):
|
def get_report(self):
|
||||||
|
|
||||||
report = bytes(self.report)
|
report = bytes(self.report)
|
||||||
|
print(format_msg_controller(report))
|
||||||
# Clear report
|
# Clear report
|
||||||
self.set_empty_report()
|
self.set_empty_report()
|
||||||
return report
|
return report
|
||||||
|
|
@ -266,22 +267,35 @@ class ControllerProtocol():
|
||||||
self.report[5] = self.button_status[1]
|
self.report[5] = self.button_status[1]
|
||||||
self.report[6] = self.button_status[2]
|
self.report[6] = self.button_status[2]
|
||||||
|
|
||||||
self.report[7] = self.left_stick_status[0]
|
self.report[7] = self.left_stick_centre[0]
|
||||||
self.report[8] = self.left_stick_status[1]
|
self.report[8] = self.left_stick_centre[1]
|
||||||
self.report[9] = self.left_stick_status[2]
|
self.report[9] = self.left_stick_centre[2]
|
||||||
|
|
||||||
self.report[10] = self.right_stick_status[0]
|
self.report[10] = self.right_stick_centre[0]
|
||||||
self.report[11] = self.right_stick_status[1]
|
self.report[11] = self.right_stick_centre[1]
|
||||||
self.report[12] = self.right_stick_status[2]
|
self.report[12] = self.right_stick_centre[2]
|
||||||
|
|
||||||
self.report[13] = self.vibrator_report
|
self.report[13] = self.vibrator_report
|
||||||
|
|
||||||
def set_button_inputs(self, upper, shared, lower):
|
def set_button_inputs(self, upper, shared, lower):
|
||||||
|
|
||||||
|
print(upper, shared, lower)
|
||||||
self.report[4] = upper
|
self.report[4] = upper
|
||||||
self.report[5] = shared
|
self.report[5] = shared
|
||||||
self.report[6] = lower
|
self.report[6] = lower
|
||||||
|
|
||||||
|
def set_left_stick_inputs(self, left):
|
||||||
|
|
||||||
|
self.report[7] = left[0]
|
||||||
|
self.report[8] = left[1]
|
||||||
|
self.report[9] = left[2]
|
||||||
|
|
||||||
|
def set_right_stick_inputs(self, right):
|
||||||
|
|
||||||
|
self.report[10] = right[0]
|
||||||
|
self.report[11] = right[1]
|
||||||
|
self.report[12] = right[2]
|
||||||
|
|
||||||
def set_device_info(self):
|
def set_device_info(self):
|
||||||
|
|
||||||
# ACK Reply
|
# ACK Reply
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,6 @@ class ControllerServer():
|
||||||
if self.task_queue:
|
if self.task_queue:
|
||||||
try:
|
try:
|
||||||
msg = self.task_queue.get_nowait()
|
msg = self.task_queue.get_nowait()
|
||||||
print(msg)
|
|
||||||
if msg:
|
if msg:
|
||||||
self.input.buffer_macro(
|
self.input.buffer_macro(
|
||||||
msg["macro"], msg["macro_id"])
|
msg["macro"], msg["macro_id"])
|
||||||
|
|
@ -115,8 +114,8 @@ class ControllerServer():
|
||||||
self.input.set_protocol_input(state=self.state)
|
self.input.set_protocol_input(state=self.state)
|
||||||
msg = self.protocol.get_report()
|
msg = self.protocol.get_report()
|
||||||
|
|
||||||
if reply:
|
# if reply:
|
||||||
print(format_msg_controller(msg))
|
# print(format_msg_controller(msg))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
itr.sendall(msg)
|
itr.sendall(msg)
|
||||||
|
|
@ -168,6 +167,7 @@ class ControllerServer():
|
||||||
self.bt.address,
|
self.bt.address,
|
||||||
colour_body=self.colour_body,
|
colour_body=self.colour_body,
|
||||||
colour_buttons=self.colour_buttons)
|
colour_buttons=self.colour_buttons)
|
||||||
|
self.input.reassign_protocol(self.protocol)
|
||||||
|
|
||||||
if self.lock:
|
if self.lock:
|
||||||
self.lock.acquire()
|
self.lock.acquire()
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,16 @@ import os
|
||||||
import dbus
|
import dbus
|
||||||
|
|
||||||
from .controller import ControllerServer
|
from .controller import ControllerServer
|
||||||
|
from .controller import ControllerTypes
|
||||||
from .bluez import find_objects, toggle_input_plugin
|
from .bluez import find_objects, toggle_input_plugin
|
||||||
from .bluez import SERVICE_NAME, ADAPTER_INTERFACE
|
from .bluez import SERVICE_NAME, ADAPTER_INTERFACE
|
||||||
|
|
||||||
|
|
||||||
|
JOYCON_L = ControllerTypes.JOYCON_L
|
||||||
|
JOYCON_R = ControllerTypes.JOYCON_R
|
||||||
|
PRO_CONTROLLER = ControllerTypes.PRO_CONTROLLER
|
||||||
|
|
||||||
|
|
||||||
class NxbtCommands(Enum):
|
class NxbtCommands(Enum):
|
||||||
|
|
||||||
CREATE_CONTROLLER = 0
|
CREATE_CONTROLLER = 0
|
||||||
|
|
@ -147,7 +153,7 @@ class Nxbt():
|
||||||
|
|
||||||
# Block until the controller is ready
|
# Block until the controller is ready
|
||||||
# This needs to be done to prevent race conditions
|
# This needs to be done to prevent race conditions
|
||||||
# on DBus resources.
|
# on Bluetooth resources.
|
||||||
if type(controller_index) == int:
|
if type(controller_index) == int:
|
||||||
while True:
|
while True:
|
||||||
if controller_index in self.manager_state.keys():
|
if controller_index in self.manager_state.keys():
|
||||||
|
|
@ -157,7 +163,6 @@ class Nxbt():
|
||||||
break
|
break
|
||||||
finally:
|
finally:
|
||||||
self.__controller_lock.release()
|
self.__controller_lock.release()
|
||||||
pass
|
|
||||||
|
|
||||||
return controller_index
|
return controller_index
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ from time import perf_counter
|
||||||
from nxbt import toggle_input_plugin
|
from nxbt import toggle_input_plugin
|
||||||
from nxbt import BlueZ
|
from nxbt import BlueZ
|
||||||
from nxbt import Controller
|
from nxbt import Controller
|
||||||
from nxbt import ControllerTypes
|
from nxbt import JOYCON_L, JOYCON_R, PRO_CONTROLLER
|
||||||
|
|
||||||
|
|
||||||
JCL_REPLY02 = b'\xA2\x21\x05\x8E\x84\x00\x12\x01\x18\x80\x01\x18\x80\x80\x82\x02\x03\x48\x01\x02\xDC\xA6\x32\x16\x4A\x7C\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
JCL_REPLY02 = b'\xA2\x21\x05\x8E\x84\x00\x12\x01\x18\x80\x01\x18\x80\x80\x82\x02\x03\x48\x01\x02\xDC\xA6\x32\x16\x4A\x7C\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||||
|
|
@ -95,10 +95,10 @@ if __name__ == "__main__":
|
||||||
# Switch Controller Bluetooth MAC Address goes here
|
# Switch Controller Bluetooth MAC Address goes here
|
||||||
jc_MAC = "7C:BB:8A:FA:41:3D"
|
jc_MAC = "7C:BB:8A:FA:41:3D"
|
||||||
# Specify the type of controller here
|
# Specify the type of controller here
|
||||||
controller_type = ControllerTypes.PRO_CONTROLLER
|
controller_type = PRO_CONTROLLER
|
||||||
if controller_type == ControllerTypes.JOYCON_L:
|
if controller_type == JOYCON_L:
|
||||||
REPLY = JCL_REPLY02
|
REPLY = JCL_REPLY02
|
||||||
elif controller_type == ControllerTypes.JOYCON_R:
|
elif controller_type == JOYCON_R:
|
||||||
REPLY = JCR_REPLY02
|
REPLY = JCR_REPLY02
|
||||||
else:
|
else:
|
||||||
REPLY = PRO_REPLY02
|
REPLY = PRO_REPLY02
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ data_right[5] = (stick_cal_right[8] << 4) | (stick_cal_right[7] >> 4)
|
||||||
# Left Stick Decode
|
# Left Stick Decode
|
||||||
left_center_x = data_left[2]
|
left_center_x = data_left[2]
|
||||||
left_center_y = data_left[3]
|
left_center_y = data_left[3]
|
||||||
left_x_min = left_center_x - data_left[0]
|
left_x_min = (left_center_x - data_left[0]) - left_center_x
|
||||||
left_x_max = left_center_x + data_left[4]
|
left_x_max = (left_center_x + data_left[4]) - left_center_x
|
||||||
left_y_min = left_center_y - data_left[1]
|
left_y_min = (left_center_y - data_left[1]) - left_center_y
|
||||||
left_y_max = left_center_y + data_left[5]
|
left_y_max = (left_center_y + data_left[5]) - left_center_y
|
||||||
|
|
||||||
print("Left Stick Values:")
|
print("Left Stick Values:")
|
||||||
print("~~~~~~~~~~~~~~~~~~")
|
print("~~~~~~~~~~~~~~~~~~")
|
||||||
|
|
@ -38,10 +38,10 @@ print("Left Y Min/Max: ", left_y_min, "", left_y_max)
|
||||||
# Right Stick Decode
|
# Right Stick Decode
|
||||||
right_center_x = data_right[0]
|
right_center_x = data_right[0]
|
||||||
right_center_y = data_right[1]
|
right_center_y = data_right[1]
|
||||||
right_x_min = right_center_x - data_right[2]
|
right_x_min = (right_center_x - data_right[2]) - right_center_x
|
||||||
right_x_max = right_center_x + data_right[4]
|
right_x_max = (right_center_x + data_right[4]) - right_center_x
|
||||||
right_y_min = right_center_y - data_right[3]
|
right_y_min = (right_center_y - data_right[3]) - right_center_y
|
||||||
right_y_max = right_center_y + data_right[5]
|
right_y_max = (right_center_y + data_right[5]) - right_center_y
|
||||||
|
|
||||||
print("\nRight Stick Values:")
|
print("\nRight Stick Values:")
|
||||||
print("~~~~~~~~~~~~~~~~~~~")
|
print("~~~~~~~~~~~~~~~~~~~")
|
||||||
|
|
@ -63,9 +63,20 @@ print("Relative X/Y Values", ratio_x, ratio_y)
|
||||||
|
|
||||||
print("\nExample Left Stick Ratio to Data Conversion:")
|
print("\nExample Left Stick Ratio to Data Conversion:")
|
||||||
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
|
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||||
data_x_converted = (abs(ratio_x) * (left_x_min - left_center_x) + left_center_x)
|
if ratio_x < 0:
|
||||||
|
data_x_converted = (
|
||||||
|
abs(ratio_x) * (left_x_min - left_center_x) + left_center_x)
|
||||||
|
else:
|
||||||
|
data_x_converted = (
|
||||||
|
abs(ratio_x) * (left_x_max - left_center_x) + left_center_x)
|
||||||
data_x_converted = int(round(data_x_converted))
|
data_x_converted = int(round(data_x_converted))
|
||||||
data_y_converted = (abs(ratio_y) * (left_y_min - left_center_y) + left_center_y)
|
|
||||||
|
if ratio_y < 0:
|
||||||
|
data_y_converted = (
|
||||||
|
abs(ratio_y) * (left_y_min - left_center_y) + left_center_y)
|
||||||
|
else:
|
||||||
|
data_y_converted = (
|
||||||
|
abs(ratio_y) * (left_y_max - left_center_y) + left_center_y)
|
||||||
data_y_converted = int(round(data_y_converted))
|
data_y_converted = int(round(data_y_converted))
|
||||||
print("X/Y Converted Values:", data_x_converted, data_y_converted)
|
print("X/Y Converted Values:", data_x_converted, data_y_converted)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,5 +43,5 @@ filterwarnings =
|
||||||
error
|
error
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 80
|
max-line-length = 100
|
||||||
exclude = .git, .eggs, __pycache__, tests/, docs/, build/, dist/
|
exclude = .git, .eggs, __pycache__, tests/, docs/, build/, dist/
|
||||||
Loading…
Add table
Add a link
Reference in a new issue