77import socket
88import struct
99import threading
10+ from enum import IntEnum
1011from typing import TYPE_CHECKING , Any , List , Optional
1112
1213import Utils
@@ -44,6 +45,11 @@ def __init__(self, command: bytes, timeout: float = 10.0):
4445 self .future = asyncio .get_running_loop ().create_future () # asyncio.Future()
4546 self .timestamp = time .time ()
4647
48+ class CommandID (IntEnum ):
49+ CONNECT = 0
50+ DISCONNECT = 1
51+ ITEM = 2
52+
4753class AsyncWiiMemoryClient :
4854 def __init__ (self , wii_ip , port = 51234 ):
4955 self .wii_ip = wii_ip
@@ -64,7 +70,7 @@ async def connect(self):
6470 logger .info (f"port: { self .port } " )
6571 self .transport , self .protocol = await loop .create_datagram_endpoint (
6672 lambda : AsyncUDPProtocol (self ),
67- local_addr = ("" , 51235 ), # try empty string for ip/port
73+ local_addr = ("0.0.0.0 " , 51235 ), # try empty string for ip/port
6874 remote_addr = (self .wii_ip , self .port )
6975 )
7076 sock = self .transport .get_extra_info ('socket' )
@@ -111,22 +117,9 @@ def handle_response(self, data):
111117
112118 async def establish_connections (self , timeout = 1 ):
113119 """Try to send a packet with IP and Port to establish connection to Wii server"""
114- packet_size = 7
115-
116- command = packet_size .to_bytes (4 , byteorder = "big" )
117-
118- response = await self ._send_command_queued (command , timeout )
119-
120- command = b'\x00 ' + socket .inet_aton (self .my_ip ) + struct .pack ('>H' , self .my_port )
121-
122- response = await self ._send_command_queued (command , timeout )
123-
124- logger .info (response )
125-
126- if len (response ) > 0 :
127- return True
128- else :
129- raise Exception (f"Establishing UDP connection failed" )
120+ # tell the wii who to return packets to
121+ packet = socket .inet_aton (self .my_ip ) + struct .pack ('>H' , self .my_port )
122+ await self .send_packet (packet , packet_type_id = CommandID .CONNECT )
130123
131124 async def _send_command_queued (self , command : bytes , timeout = 2 ):
132125 """Queue up command to read/write to console"""
@@ -174,16 +167,9 @@ async def _handle_request_timeout(self, request: CommandRequest):
174167 except asyncio .CancelledError :
175168 pass
176169
177- async def signal_dc (self , timeout = 2 ) -> bytes :
170+ async def signal_dc (self , timeout = 2 ):
178171 """Send a signal to the wii that the client lost connection"""
179- command = struct .pack ('>B' , 0x05 ) # DISCONNECT - 0x05
180-
181- response = await self ._send_command_queued (command , timeout )
182-
183- if len (response ) > 0 :
184- return response
185- else :
186- raise Exception (f"Read failed at address" )
172+ await self .send_packet (bytes (), packet_type_id = CommandID .DISCONNECT )
187173
188174 def close (self ):
189175 """Close connection"""
@@ -192,32 +178,24 @@ def close(self):
192178 self .transport .close ()
193179 self .transport = None
194180
181+ async def send_packet (self , data , packet_type_id , timeout = 2 ):
182+ """Send a single packet to the wii client"""
195183
196- async def write_bytes (self , data , packet_type_id = 0 , timeout = 2 ):
197- if packet_type_id == 0 :
198- raise Exception (f"invalid packet type id with data: { data } " )
199-
200- data_len = len (data )
201-
202- packet_size = data_len .to_bytes (4 , byteorder = "big" )
203-
204- response = await self ._send_command_queued (packet_size , timeout )
184+ packet = bytearray ()
185+ packet += struct .pack (">B" , packet_type_id ) # id: u8
186+ packet += data # data: byte[]
205187
206- if len (response ) != 1 :
207- raise Exception (f"Write failed with data { data } " )
188+ if len (packet ) > 512 :
189+ raise Exception ("Cannot send more than 512 bytes per packet " )
208190
209- packet_type_id = packet_type_id . to_bytes ( 1 , byteorder = "big " )
191+ print ( f"[send_packet] id= { packet_type_id } , data= { data } " )
210192
211- command = packet_type_id + data
212-
213- logger .info (f"Command: { command } | Data Length: { data_len } | Data: { data .hex ()} " )
214-
215- response = await self ._send_command_queued (command , timeout )
216-
217- if len (response ) == 1 :
193+ # expect 0xAA byte for ack
194+ response = await self ._send_command_queued (packet , timeout )
195+ if len (response ) == 1 and response [0 ] == 0xAA :
218196 return True
219- else :
220- raise Exception (f"Write failed with data { data } " )
197+
198+ raise Exception (f"Packet went unacknowledged: { packet } " )
221199
222200class WSRCommandProcessor (ClientCommandProcessor ):
223201 """
@@ -372,7 +350,7 @@ async def _give_item(self, item_name: str) -> bool:
372350
373351 logger .info (f"item id in bytes: { item_id_byte } " )
374352
375- if await self .wii_memory_client .write_bytes (item_id_byte , packet_type_id = 1 ):
353+ if await self .wii_memory_client .send_packet (item_id_byte , packet_type_id = CommandID . ITEM ):
376354 logger .info ("sent item" )
377355 return True
378356
0 commit comments