Added prelim parallel architecture
This commit is contained in:
parent
9ea8f94277
commit
ff9e1313b8
4 changed files with 158 additions and 26 deletions
31
demo.py
31
demo.py
|
|
@ -1,30 +1,15 @@
|
|||
import threading
|
||||
import time
|
||||
|
||||
from nxbt import ControllerServer
|
||||
from nxbt import Nxbt
|
||||
from nxbt import ControllerTypes
|
||||
|
||||
# con = ControllerServer(ControllerTypes.JOYCON_R)
|
||||
# con.run()
|
||||
# # con.run(reconnect_address="7C:BB:8A:D9:91:5A")
|
||||
|
||||
|
||||
def thread_func_1():
|
||||
|
||||
print("Starting Thread 1")
|
||||
con = ControllerServer(ControllerTypes.JOYCON_R)
|
||||
con.run()
|
||||
|
||||
|
||||
def thread_func_2():
|
||||
|
||||
print("Starting Thread 2")
|
||||
time.sleep(10)
|
||||
con = ControllerServer(ControllerTypes.JOYCON_L)
|
||||
con.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
x = threading.Thread(target=thread_func_1)
|
||||
x.start()
|
||||
nxbt = Nxbt()
|
||||
index = nxbt.create_controller(
|
||||
ControllerTypes.PRO_CONTROLLER, "/org/bluez/hci0")
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
||||
print(nxbt.get_state())
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ from .controller import ControllerProtocol
|
|||
from .controller import SwitchReportParser
|
||||
from .controller import SwitchResponses
|
||||
from .controller import Controller
|
||||
from .bluez import BlueZ
|
||||
|
||||
from .bluez import *
|
||||
from .nxbt import Nxbt
|
||||
|
|
|
|||
|
|
@ -1,2 +1,5 @@
|
|||
from .web import start_web_app
|
||||
|
||||
|
||||
def main():
|
||||
raise NotImplementedError()
|
||||
start_web_app()
|
||||
|
|
|
|||
144
nxbt/nxbt.py
Normal file
144
nxbt/nxbt.py
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
from multiprocessing import Process, Lock
|
||||
from multiprocessing import Queue, Manager
|
||||
import queue
|
||||
from enum import Enum
|
||||
import atexit
|
||||
|
||||
import dbus
|
||||
|
||||
from .controller import ControllerServer
|
||||
from .bluez import find_objects, SERVICE_NAME, ADAPTER_INTERFACE
|
||||
|
||||
|
||||
class NxbtCommands(Enum):
|
||||
|
||||
CREATE_CONTROLLER = 0
|
||||
|
||||
|
||||
class Nxbt():
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# Main queue for nbxt tasks
|
||||
self.task_queue = Queue()
|
||||
|
||||
# Creates/manages shared resources
|
||||
self.resource_manager = Manager()
|
||||
# Shared dictionary for viewing overall nxbt state.
|
||||
# Should only be read by threads and wrote to by
|
||||
# the main nxbt multiprocessing process.
|
||||
self.state = self.resource_manager.dict()
|
||||
|
||||
# Shared, controller management properties.
|
||||
# The controller lock is used to sychronize use.
|
||||
self.__controller_lock = Lock()
|
||||
self.__controller_counter = 0
|
||||
self.__adapters_in_use = []
|
||||
|
||||
# Exit handler
|
||||
atexit.register(self.on_exit)
|
||||
|
||||
# Starting the nxbt worker process
|
||||
self.controllers = Process(
|
||||
target=self.__command_manager,
|
||||
args=((self.task_queue), (self.state)))
|
||||
# Disabling daemonization since we need to spawn
|
||||
# other controller processes, however, this means
|
||||
# we need to cleanup on exit.
|
||||
self.controllers.daemon = False
|
||||
self.controllers.start()
|
||||
|
||||
def on_exit(self):
|
||||
|
||||
# Need to explicitly kill the controllers process
|
||||
# since it isn't daemonized.
|
||||
if hasattr(self, "controllers") and self.controllers.is_alive():
|
||||
self.controllers.terminate()
|
||||
|
||||
def __command_manager(self, task_queue, state):
|
||||
|
||||
cm = ControllerManager(state)
|
||||
|
||||
while True:
|
||||
|
||||
try:
|
||||
msg = task_queue.get_nowait()
|
||||
except queue.Empty:
|
||||
msg = None
|
||||
|
||||
if msg:
|
||||
if msg["command"] == NxbtCommands.CREATE_CONTROLLER:
|
||||
cm.create_controller(
|
||||
msg["arguments"]["controller_index"],
|
||||
msg["arguments"]["controller_type"],
|
||||
msg["arguments"]["adapter_path"])
|
||||
|
||||
def send_input(self, msg):
|
||||
|
||||
self.task_queue.put(msg)
|
||||
|
||||
def create_controller(self, controller_type, adapter_path):
|
||||
|
||||
if adapter_path not in self.get_available_adapters():
|
||||
raise ValueError("Specified adapter is unavailable")
|
||||
|
||||
if adapter_path in self.__adapters_in_use:
|
||||
raise ValueError("Specified adapter in use")
|
||||
|
||||
controller_index = None
|
||||
try:
|
||||
self.__controller_lock.acquire()
|
||||
self.task_queue.put({
|
||||
"command": NxbtCommands.CREATE_CONTROLLER,
|
||||
"arguments": {
|
||||
"controller_index": self.__controller_counter,
|
||||
"controller_type": controller_type,
|
||||
"adapter_path": adapter_path,
|
||||
}
|
||||
})
|
||||
controller_index = self.__controller_counter
|
||||
self.__controller_counter += 1
|
||||
self.__adapters_in_use.append(adapter_path)
|
||||
finally:
|
||||
self.__controller_lock.release()
|
||||
pass
|
||||
|
||||
return controller_index
|
||||
|
||||
def get_available_adapters(self):
|
||||
|
||||
bus = dbus.SystemBus()
|
||||
adapters = find_objects(bus, SERVICE_NAME, ADAPTER_INTERFACE)
|
||||
|
||||
return adapters
|
||||
|
||||
def get_state(self):
|
||||
|
||||
return self.state
|
||||
|
||||
|
||||
class ControllerManager():
|
||||
|
||||
def __init__(self, state):
|
||||
|
||||
self.state = state
|
||||
self.controller_states = []
|
||||
self.controller_queues = []
|
||||
|
||||
def create_controller(self, index, controller_type, adapter_path):
|
||||
|
||||
controller_queue = Queue()
|
||||
controller_state = {
|
||||
"state": "initializing",
|
||||
"finished_macros": [],
|
||||
"errors": False
|
||||
}
|
||||
self.state[index] = controller_state
|
||||
# Get the last parameter of the path, AKA the ID
|
||||
device_id = adapter_path.split("/")[-1]
|
||||
|
||||
server = ControllerServer(controller_type, bt_device_id=device_id)
|
||||
controller = Process(target=server.run, args=(
|
||||
None, controller_state, controller_queue))
|
||||
controller.daemon = True
|
||||
controller.start()
|
||||
Loading…
Add table
Add a link
Reference in a new issue