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 import time
from nxbt import ControllerServer from nxbt import Nxbt
from nxbt import ControllerTypes 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__": if __name__ == "__main__":
x = threading.Thread(target=thread_func_1) nxbt = Nxbt()
x.start() 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 SwitchReportParser
from .controller import SwitchResponses from .controller import SwitchResponses
from .controller import Controller 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(): 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()