Added prelim parallel architecture

This commit is contained in:
Brikwerk 2020-05-27 01:17:37 -07:00
commit ff9e1313b8
4 changed files with 158 additions and 26 deletions

31
demo.py
View file

@ -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())

View file

@ -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

View file

@ -1,2 +1,5 @@
from .web import start_web_app
def main():
raise NotImplementedError()
start_web_app()

144
nxbt/nxbt.py Normal file
View 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()