Skip to content

Commit

Permalink
Threads notify GUI on crash (+4 squashed commits)
Browse files Browse the repository at this point in the history
  - Fixes #19

Cleaned up command responses a bit

Add a method to send random audio to the Wii U

Cleaned input controller

Add command for micrphone input (random)
  • Loading branch information
rolandoislas committed Apr 18, 2017
1 parent 9e6b021 commit 66e6654
Show file tree
Hide file tree
Showing 14 changed files with 361 additions and 173 deletions.
61 changes: 35 additions & 26 deletions drc-info.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from threading import Thread

from src.server.data import constants
from src.server.data.struct import input
from src.server.data.struct import input, command

sock_cmd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_cmd.bind(("192.168.1.10", constants.PORT_WII_CMD))
Expand All @@ -22,44 +22,53 @@

def print_packet(sock, name):
data = sock.recv(2048)
print("%s: %s" % (name, codecs.encode(data, "hex")))
print("%s: %s" % (name, codecs.encode(data, "hex").decode()))


def send_cmd(data):
sock_cmd.sendto(data, ("192.168.1.11", constants.PORT_WII_CMD + 100))


def send_command_from_string(command_string, sid):
send_data = command.header.parse(codecs.decode(command_string, "hex"))
send_data.seq_id = sid
if send_data.cmd_id == 1:
send_data.mic_enabled = 0 # floods logs with audio data if enabled
send_data = command.header.build(send_data)
send_cmd(send_data)
sid += 1
sid %= 65535
time.sleep(1)
return sid


def cmd_request():
sid = 0
while True:
data = {
0: {0: {0: "000000000c00%s087e0115880040000000000000",
10: "000000000d00%s007e0101780040000a0000000100"},
4: {4: "000000000c00%s007e0109780040040400000000",
10: "000000000d00%s117e012fc80040040a0000000100",
11: "000000000c00%s017e0107180040040b00000000"},
5: {6: "000000000c00%s007e0101a80040050600000000",
12: "000000001100%s007e0102f80040050c000000050e0300870f",
16: "000001003000%s80010000000000000000000000803e0000000100029e0000000000000070000000404003002d0000"
0: {0: {0: "000000000c0005087e0115880040000000000000",
10: "000000000d0005007e0101780040000a0000000100"},
4: {4: "000000000c0005007e0109780040040400000000",
10: "000000000d0005117e012fc80040040a0000000100",
11: "000000000c0005017e0107180040040b00000000"},
5: {6: "000000000c0005007e0101a80040050600000000",
12: "00000000110005007e0102f80040050c000000050e0300870f",
16: "0000010030000580010000000000000000000000803e0000000100029e0000000000000070000000404003002d0000"
"018000400000000000",
24: "000000001600%s007e0101c8004005180000000a54313936333030303030"}
24: "00000000160005007e0101c8004005180000000a54313936333030303030"}
},
1: {0: {0: "000001003000%s1a010000000000000000000000803e000000010002000000000000000070000000404003002d00000"
"10000000000000000" # Just CMD 1 - keys 0 0 are there so it fits nicely with the for loop
}
}
1: "000001003000051a010000000000000000000000803e000000010002000000000000000070000000404003002d00000"
"10000000000000000"
}
for command in data.keys():
for primary_id in data[command].keys():
for secondary_id in data[command][primary_id].keys():
h = hex(sid).replace("0x", "")
if len(h) == 1:
h = "0" + h
send_data = bytes(codecs.decode(data[command][primary_id][secondary_id] % h, "hex"))
print("Sending command %d %d %d" % (command, primary_id, secondary_id))
send_cmd(send_data)
sid += 1
time.sleep(1)
for cmd in data.keys():
if isinstance(data[cmd], str):
print("Sending command %d" % cmd)
sid = send_command_from_string(data[cmd], sid)
else:
for primary_id in data[cmd].keys():
for secondary_id in data[cmd][primary_id].keys():
print("Sending command %d %d %d" % (cmd, primary_id, secondary_id))
sid = send_command_from_string(data[cmd][primary_id][secondary_id], sid)


def print_hid(sock):
Expand Down
16 changes: 16 additions & 0 deletions drc-sim-backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@


def init_loggers():
"""
Initialize loggers with a specified log level if they have the argument.
:return: None
"""
loggers = (Logger, LoggerBackend, LoggerGui, LoggerCli, LoggerWpa)
for logger in loggers:
if Args.args.debug:
Expand All @@ -27,6 +31,10 @@ def init_loggers():


def start():
"""
Main loop. It can be GUI or CLI based on args. Dies if an error makes it way here or main loop stops.
:return: None
"""
ui = None
try:
if Args.args.cli:
Expand All @@ -47,6 +55,10 @@ def start():


def log_level():
"""
Log at every level to display the levels that are enabled.
:return: None
"""
# Logger info
Logger.debug("Debug logging enabled")
Logger.extra("Extra debug logging enabled")
Expand All @@ -57,6 +69,10 @@ def log_level():


def main():
"""
Main entry point. Parses arguments, loads configuration files, initialized loggers and starts the main loop.
:return: None
"""
Args.parse_args()
ConfigServer.load()
ConfigServer.save()
Expand Down
20 changes: 10 additions & 10 deletions resources/command/na.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
{
"0": {
"0": {
"0": "0200000014000c087e0115880009000000000008190c0117190c0117",
"10": "02000000100007007e0101780009000a0000000400170200"
"0": "190c0117190c0117",
"10": "00170200"
},
"3": {
"6": "000000000000000000000000000000000000000000"
"6": "00"
},
"4": {
"4": "02000000280008007e010978000904040000001c0000000b00000040190c011728000058000800000c0221fe00001c58",
"10": "020000000c0002117e012fc80009040a00000000",
"11": "020000000d000a017e0107180009040b0000000100"
"4": "0000000b00000040190c011728000058000800000c0221fe00001c58",
"10": "",
"11": "00"
},
"5": {
"6": "0000000000000000000000000000000000000000280000580000000000000000000000000000000000000000000000000000000000000000001000800300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000405132000206d336213160525064cbe7470cca8a7e79f3b470ea34af2ca04bc67049010e1e24a16800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c3d8b5c35010e1e15ab48000000000000000000000000000000b8f006ff10abbcff200011ff6f1f611f551e6052c50000f0ffff0900003a5c02325702d05b02c8d26600000000000000000000000000000000000035001e002203c30153015d0ea90e9b0166aee41703a0b5430000000000000000000000000000000000000000008b5c35010e1e15ab48000000000000000000000000000000b8f006ff10abbcff200011ff6f1f611f551e6052c50000f0ffff0900003a5c02325702d05b02c8d26600000000000000000000000000000000000035001e002203c30153015d0ea90e9b0166aee41703a0b543000000000000000000000000000000000000052a5800870f00870f010e1e00000000001900161d6fbcff200011ff6f1f611f551e605200000000000000000000000000000000000000000000000000000000000000000000005d007800f8028201fc01920bf10d6c03481a01000217144800000003ba31e41703a0b54300000000000000000000000000870f15012d014d017a01b701ff0103268c04a34954313936335331333737780100870f00870f010e1effff0000870f00870f020008c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004a349",
"12": "020000000c0009007e0102f80009050c00000000",
"24": "020000000c0003007e0101c80009051800000000"
"6": "280000580000000000000000000000000000000000000000000000000000000000000000001000800300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000405132000206d336213160525064cbe7470cca8a7e79f3b470ea34af2ca04bc67049010e1e24a16800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000031c3d8b5c35010e1e15ab48000000000000000000000000000000b8f006ff10abbcff200011ff6f1f611f551e6052c50000f0ffff0900003a5c02325702d05b02c8d26600000000000000000000000000000000000035001e002203c30153015d0ea90e9b0166aee41703a0b5430000000000000000000000000000000000000000008b5c35010e1e15ab48000000000000000000000000000000b8f006ff10abbcff200011ff6f1f611f551e6052c50000f0ffff0900003a5c02325702d05b02c8d26600000000000000000000000000000000000035001e002203c30153015d0ea90e9b0166aee41703a0b543000000000000000000000000000000000000052a5800870f00870f010e1e00000000001900161d6fbcff200011ff6f1f611f551e605200000000000000000000000000000000000000000000000000000000000000000000005d007800f8028201fc01920bf10d6c03481a01000217144800000003ba31e41703a0b54300000000000000000000000000870f15012d014d017a01b701ff0103268c04a34954313936335331333737780100870f00870f010e1effff0000870f00870f020008c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004a349",
"12": "",
"24": ""
}
},
"1": "0200010010000b1a000000009e0000008000400000000158"
"1": "000000009e0000008000400000000158"
}
57 changes: 45 additions & 12 deletions src/server/control/gamepad.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,71 @@
from src.server.net import socket_handlers
from src.server.net import sockets
from src.server.util.logging.logger_backend import LoggerBackend
from src.server.util.status_sending_thread import StatusSendingThread


class Gamepad:
class Gamepad(StatusSendingThread):
NO_PACKETS = "NO_PACKETS"
STOPPED = "STOPPED"
RUNNING = "RUNNING"
WAITING_FOR_PACKET = "WAITING_FOR_PACKET"
CRASHED = "CRASHED"

def __init__(self):
"""
Backend server handler. Processes packets from the Wii U and servers clients.
"""
super().__init__()
self.backend_thread = None
self.status = self.STOPPED
self.status_change_listeners = []
self.set_status(self.STOPPED)
self.running = False
self.wii_packet_time = time.time()
self.has_received_packet = False
self.server = Server()

def start(self):
"""
Start the main thread
:return: None
"""
ConfigServer.load()
ConfigServer.save()
self.print_init()
sockets.Sockets.connect()
socket_handlers.SocketHandlers.create()
self.running = True
LoggerBackend.debug("Starting backend thread")
self.backend_thread = Thread(target=self.update)
self.backend_thread = Thread(target=self.update, name="Backend Thread")
self.backend_thread.start()
LoggerBackend.debug("Post backend thread")

def print_init(self):
"""
Log the initialization messages
:return: None
"""
LoggerBackend.info("Started drc-sim-backend")
self.print_config()
LoggerBackend.info("Waiting for Wii U packets")

@staticmethod
def handle_wii_packet(sock):
"""
Receive data from a socket and pass it to the appropriate packet handler.
:param sock: Wii U datagram Socket
:return: None
"""
data = sock.recv(2048)
try:
socket_handlers.SocketHandlers.wii_handlers[sock].update(data)
except socket.error as e:
LoggerBackend.warn(str(e) + str(e.errno))

def handle_sockets(self):
"""
Check if any sockets have data and pass then to their handler.
:return: None
"""
# Group all sockets
rlist, wlist, xlist = select.select(socket_handlers.SocketHandlers.get_handler_keys(),
(), (), 0.001)
Expand All @@ -74,15 +96,24 @@ def handle_sockets(self):
self.server.handle_client_command_packet(sock)

def update(self):
"""
Main loop
:return: None
"""
while self.running:
try:
self.check_last_packet_time()
self.handle_sockets()
Controller.update()
except Exception as e:
self.set_status(self.CRASHED)
LoggerBackend.throw(e)

def close(self):
"""
Stop the backend thread
:return: None
"""
if not self.running:
LoggerBackend.debug("Ignored stop request: already stopped")
return
Expand All @@ -98,27 +129,29 @@ def close(self):
s.close()
LoggerBackend.debug("Closing sockets")
sockets.Sockets.close()
self.status_change_listeners = []
self.clear_status_change_listeners()
LoggerBackend.debug("Backend closed")

def check_last_packet_time(self):
"""
Checks if the server should shutdown after not receiving packets for more than a minute
:return: None
"""
if not self.has_received_packet:
status = self.WAITING_FOR_PACKET
elif time.time() - self.wii_packet_time >= 60:
status = Gamepad.NO_PACKETS
else:
status = Gamepad.RUNNING
if self.status != status:
self.status = status
for listener in self.status_change_listeners:
listener(status)
self.set_status(status)

@staticmethod
def print_config():
"""
Logs the server configuration info
:return: None
"""
LoggerBackend.info("Config: FPS %d", ConfigServer.fps)
LoggerBackend.info("Config: Input Delay %f", ConfigServer.input_delay)
LoggerBackend.info("Config: Image Quality %d", ConfigServer.quality)
LoggerBackend.info("Config: Stream Audio %s", ConfigServer.stream_audio)

def add_status_change_listener(self, callback):
self.status_change_listeners.append(callback)
Loading

0 comments on commit 66e6654

Please sign in to comment.