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