1 /*---------------------------------------------------------------------------* 2 3 Copyright (C) Nintendo. All rights reserved. 4 5 These coded instructions, statements, and computer programs contain 6 proprietary information of Nintendo of America Inc. and/or Nintendo 7 Company Ltd., and are protected by Federal copyright law. They may 8 not be disclosed to third parties or copied or duplicated in any form, 9 in whole or in part, without the prior written consent of Nintendo. 10 11 *---------------------------------------------------------------------------*/ 12 using System; 13 using System.Collections.Generic; 14 using System.IO; 15 using System.Net; 16 using System.Net.Sockets; 17 using System.Net.NetworkInformation; 18 using System.Text; 19 20 21 namespace Nintendo.SDSG 22 { 23 public class NetworkInterfaceExplorer 24 { 25 public string ComputerName { get; private set; } 26 public string DomainName { get; private set; } 27 public IList<NetworkInterface> ActiveNICs { get; private set; } 28 public bool ConnectedToTheEther { get; private set; } 29 30 ToString()31 public override string ToString() 32 { 33 StringBuilder sb = new StringBuilder(); 34 foreach (NetworkInterface nic in ActiveNICs) 35 { 36 sb.AppendLine( GetIPv4Address(nic).ToString() ); 37 } 38 return sb.ToString(); 39 } 40 NetworkInterfaceExplorer()41 public NetworkInterfaceExplorer() 42 { 43 ReScan(); 44 } 45 ReScan()46 public void ReScan() 47 { 48 IPGlobalProperties overall_props = IPGlobalProperties.GetIPGlobalProperties(); 49 ComputerName = overall_props.HostName; 50 DomainName = overall_props.DomainName; 51 52 ConnectedToTheEther = NetworkInterface.GetIsNetworkAvailable(); 53 ActiveNICs = _get_active_ethernet_adapters(); 54 } 55 56 GetIPv4Address(NetworkInterface nic)57 public IPAddress GetIPv4Address(NetworkInterface nic) 58 { 59 foreach (var single_point_address in nic.GetIPProperties().UnicastAddresses) 60 { 61 if (single_point_address.Address.AddressFamily == AddressFamily.InterNetwork) 62 { 63 return single_point_address.Address; 64 } 65 } 66 return IPAddress.None; 67 } 68 _get_active_ethernet_adapters()69 private IList<NetworkInterface> _get_active_ethernet_adapters() 70 { 71 List<NetworkInterface> rc = new List<NetworkInterface>(); 72 73 NetworkInterface[] all_network_cards = NetworkInterface.GetAllNetworkInterfaces(); 74 foreach (var network_card in all_network_cards) 75 { 76 77 if (network_card.OperationalStatus != OperationalStatus.Up) 78 { 79 continue; 80 } 81 82 83 if (network_card.NetworkInterfaceType == NetworkInterfaceType.Loopback) continue; 84 rc.Add(network_card); 85 } 86 87 return rc; 88 } 89 GetPrettyMAC(byte[] mac_address)90 public static string GetPrettyMAC(byte[] mac_address) 91 { 92 return GetPrettyMAC(mac_address, 0); 93 } 94 GetPrettyMAC(byte[] mac_address, int starting_index_in_buffer)95 public static string GetPrettyMAC(byte[] mac_address, int starting_index_in_buffer) 96 { 97 StringBuilder sb = new StringBuilder(); 98 sb.AppendFormat("{0:x2}:{0:x2}:{0:x2}:{0:x2}:{0:x2}:{0:x2}", 99 mac_address[starting_index_in_buffer+0], 100 mac_address[starting_index_in_buffer+1], 101 mac_address[starting_index_in_buffer+2], 102 mac_address[starting_index_in_buffer+3], 103 mac_address[starting_index_in_buffer+4], 104 mac_address[starting_index_in_buffer+5]); 105 return sb.ToString(); 106 } 107 108 } 109 110 public class MionIdentifier 111 { 112 public string Name {get; private set; } 113 public string FieldProgrammableGateArrayVersion { get; private set; } 114 public string FirmwareVersion { get; private set; } 115 public string MACAddress { get; private set; } 116 public byte Flags { get; private set; } 117 public IPEndPoint NetworkAddress; 118 119 120 private const int k_flags_idx = 0; 121 private const int k_mac_addr_idx = 1; 122 private const int k_name_len_idx = 7; 123 private const int k_fpga_idx = 8; 124 private const int k_fw_ver_idx = 12; 125 private const int k_machine_name_idx = 16; 126 TryCreate(byte[] broadcast_reciept, IPEndPoint location)127 internal static MionIdentifier TryCreate(byte[] broadcast_reciept, IPEndPoint location) 128 { 129 /* 130 BYTE bFlags; // 0 131 BYTE MACAddr[6]; // 1 132 BYTE bMachineNameLength; // 7 133 BYTE FPGAVersion1; // 8 134 BYTE FPGAVersion2; // 9 135 BYTE FPGAVersion3; // 10 136 BYTE FPGAVersion4; // 11 137 BYTE FWVersion1; // 12 138 BYTE FWVersion2; // 13 139 BYTE FWVersion3; // 14 140 BYTE FWVersion4; // 15 141 char szMachineName[MAX_PATH]; // 16 142 */ 143 144 145 if (broadcast_reciept[0] == (byte)MionUdp.MionCmdByte.Acknowledge) 146 { 147 return new MionIdentifier(broadcast_reciept, location); 148 } 149 150 return null; 151 152 } 153 154 MionIdentifier(byte[] broadcast_reciept, IPEndPoint location)155 private MionIdentifier(byte[] broadcast_reciept, IPEndPoint location) 156 { 157 Flags = broadcast_reciept[k_flags_idx]; 158 MACAddress = NetworkInterfaceExplorer.GetPrettyMAC(broadcast_reciept, k_mac_addr_idx); 159 Name = ASCIIEncoding.ASCII.GetString(broadcast_reciept, k_machine_name_idx, broadcast_reciept[k_name_len_idx]); 160 NetworkAddress = location; 161 162 FieldProgrammableGateArrayVersion = String.Format("{0}.{1}.{2}.{3}", broadcast_reciept[k_fpga_idx + 0], 163 broadcast_reciept[k_fpga_idx + 1], broadcast_reciept[k_fpga_idx + 2], broadcast_reciept[k_fpga_idx + 3]); 164 165 FirmwareVersion = String.Format("{0}.{1}.{2}.{3}", broadcast_reciept[k_fw_ver_idx + 0], 166 broadcast_reciept[k_fw_ver_idx + 1], broadcast_reciept[k_fw_ver_idx + 2], broadcast_reciept[k_fw_ver_idx + 3]); 167 } 168 169 ToString()170 public override string ToString() 171 { 172 StringBuilder sb = new StringBuilder(); 173 sb.AppendFormat("{0,-16}: {3,-25} - FW {1} - FPGA {2}", NetworkAddress.Address, FirmwareVersion, FieldProgrammableGateArrayVersion, Name); 174 return sb.ToString(); 175 } 176 177 } 178 179 180 public class LocatedMions 181 { LocatedMions()182 internal LocatedMions() { } 183 184 public NetworkInterfaceExplorer NetInfo { get; internal set; } 185 public IList<MionIdentifier> Mions { get; internal set; } 186 } 187 188 189 public class NetworkTuple 190 { 191 public byte[] Item1; 192 public IPEndPoint Item2; 193 NetworkTuple(byte[] bytes, IPEndPoint endpoint)194 public NetworkTuple(byte[] bytes, IPEndPoint endpoint) 195 { 196 Item1 = bytes; 197 Item2 = endpoint; 198 } 199 } 200 201 public class MionUdp 202 { 203 const string k_mion_string = "MULTI_I/O_NETWORK_BOARD"; 204 const ushort k_mion_ctrl_port = 7974; 205 const ushort k_mion_char_port = 7975; 206 const ushort k_mion_bulk_port = 7976; 207 208 internal enum MionCmdByte 209 { 210 //Search = 0x3f, 211 //Broadcast = 0x21 212 AnnounceYourselves = 0x2a, 213 Acknowledge = 0x20, 214 } 215 216 _create_buffer_for_announce_yourselves()217 private static byte[] _create_buffer_for_announce_yourselves() 218 { 219 byte[] rc = new byte[25]; 220 rc[0] = (byte)MionCmdByte.AnnounceYourselves; 221 222 System.Text.ASCIIEncoding.ASCII.GetBytes(k_mion_string, 0, k_mion_string.Length, rc, 1); 223 return (rc); 224 } 225 226 227 ScanLocalSubnetForMIONs()228 public static LocatedMions ScanLocalSubnetForMIONs() 229 { 230 NetworkInterfaceExplorer looker = new NetworkInterfaceExplorer(); 231 232 LocatedMions rc = new LocatedMions(); 233 rc.NetInfo = looker; 234 235 if (looker.ConnectedToTheEther == false) 236 { 237 return rc; 238 } 239 240 IPAddress local_address = looker.GetIPv4Address(looker.ActiveNICs[0]); 241 IPAddress broadcast_address; 242 243 { 244 string str_local_address = local_address.ToString(); 245 string str_chopped_broadcast = str_local_address.Remove(str_local_address.LastIndexOf('.')); 246 string str_final_broadcast = str_chopped_broadcast + ".255"; 247 broadcast_address = IPAddress.Parse(str_final_broadcast); 248 } 249 250 251 IPEndPoint my_local_portcombo = new IPEndPoint(local_address, k_mion_ctrl_port); 252 IPEndPoint target_destination_portcombo = new IPEndPoint(broadcast_address, k_mion_ctrl_port); 253 254 byte[] msg_to_broadcast = _create_buffer_for_announce_yourselves(); 255 256 Socket skBroadcaster = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 257 258 skBroadcaster.Bind(my_local_portcombo); 259 skBroadcaster.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); 260 261 rc.Mions = new List<MionIdentifier>(); 262 263 DateTime current_time = DateTime.Now; 264 DateTime target_time = current_time.AddMilliseconds(10); 265 266 skBroadcaster.SendTo(msg_to_broadcast, target_destination_portcombo); 267 268 List<NetworkTuple> replies = new List<NetworkTuple>(); 269 270 while (DateTime.Now < target_time) 271 { 272 int avail = skBroadcaster.Available; 273 if (avail > 0) 274 { 275 EndPoint mion_portcombo = new IPEndPoint(IPAddress.Any, 0); 276 277 byte[] mion_incoming_message = new byte[avail]; 278 skBroadcaster.ReceiveFrom(mion_incoming_message, ref mion_portcombo); 279 280 replies.Add(new NetworkTuple(mion_incoming_message, (IPEndPoint)mion_portcombo)); 281 } 282 283 } 284 285 for (int i = 0; i < replies.Count; i++) 286 { 287 MionIdentifier a_mion = MionIdentifier.TryCreate(replies[i].Item1, replies[i].Item2); 288 if (a_mion != null) 289 rc.Mions.Add(a_mion); 290 } 291 292 skBroadcaster.Close(); 293 return rc; 294 } 295 296 } 297 298 299 300 301 /* 302 #pragma once 303 #include <windows.h> 304 305 #define MION_CONTROL_PORT 7974 306 307 #define MION_KEYWORD "MULTI_I/O_NETWORK_BOARD" 308 #define MION_SEARCH (BYTE)0x3f 309 #define MION_ENUMERATE (BYTE)0x2a 310 #define MION_ACK (BYTE)0x20 311 #define MION_BCAST (BYTE)0x21 312 #define MION_SEARCH_TIMEOUT 20000 313 314 #define FIRST_BYTE(n) (UINT32)(n&0x000000FF) 315 #define SECOND_BYTE(n) (UINT32)((n&0x0000FF00) >> 8) 316 317 #pragma pack(push, 1) 318 typedef struct _mionsearchbridgeRequest 319 { 320 BYTE bFlags; 321 char keyword[24]; 322 BYTE bMachineNameLength; 323 char szMachineName[MAX_PATH]; 324 }MION_SEARCH_REQUEST, *PMION_SEARCH_REQUEST; 325 326 typedef struct _mionglobalsearchbridgeRequest 327 { 328 BYTE bFlags; 329 char keyword[24]; 330 }MION_GLOBAL_SEARCH_REQUEST, *PMION_GLOBAL_SEARCH_REQUEST; 331 332 typedef struct _mionsearchbridgeReply 333 { 334 BYTE bFlags; 335 BYTE MACAddr[6]; 336 BYTE bMachineNameLength; 337 BYTE FPGAVersion1; 338 BYTE FPGAVersion2; 339 BYTE FPGAVersion3; 340 BYTE FPGAVersion4; 341 BYTE FWVersion1; 342 BYTE FWVersion2; 343 BYTE FWVersion3; 344 BYTE FWVersion4; 345 char szMachineName[MAX_PATH]; 346 }MION_SEARCH_REPLY, *PMION_SEARCH_REPLY; 347 #pragma pack(pop) 348 349 */ 350 351 352 /* 353 Table 4-25 List of Settings 354 Item Name 355 Description 356 Machine Name 357 Name consisting of ASCII characters. 358 (Up to 256 characters, including the terminator.) 359 MAC Address 360 MAC address allocated to MION. 361 (Reference only.) 362 Language Setting 363 Specify Automatic, Japanese, or English. 364 If you specify Automatic, it references the header information in the browser. 365 Settings for automatically getting IP address 366 Toggle use of DHCP / Auto IP UPnP [1] 367 IP Address 368 Manually-set IP address. 369 Subnet Mask 370 Manually-set subnet mask. 371 Default Gateway 372 Manually-set IP address of default gateway. 373 Settings to automatically get DNS server address 374 Toggle use of DHCP. 375 Primary DNS Server 376 Manually-set IP address of primary DNS server. 377 Secondary DNS Server 378 Manually-set IP address of secondary DNS server. 379 Ethernet Frame Size 380 Select from 1500 bytes, 3000 bytes, 4000 bytes, 5000 bytes, 6000 bytes, 7000 bytes, 8000 bytes, and 9700 bytes.[2] 381 Default Host PC IP Address 382 IP address of PC that serves as ATAPI emulator host. 383 ATAPI Emulator Port Number 384 Sets port number to use for communication with ATAPI Emulator interface. 385 (Default: 7974) 386 FIFO1 Port Number 387 Sets port number to use for communication with FIFO1. 388 (Default: 7975) 389 FIFO2 Port Number 390 Sets port number to use for communication with FIFO2. 391 (Default: 7976) 392 Size of Buffer for FIFO1 Interface 393 Select from 4KB, 32KB, 128KB, 256KB, 512KB, 1MB, 2MB, and 4MB. 394 (Default: 4KB) 395 Size of Buffer for FIFO2 Interface 396 Select from 128KB, 256KB, 512KB, 1MB, 2MB, 4MB, 8MB, and 16MB. 397 (Default: 128KB) 398 Hard Disk Bank Size Setting 399 Select from 2GB, 5GB, 10GB, 12GB, 15GB, 18GB, 21GB, and 25GB. 400 (Default: 25GB) 401 Current Bank Number of Hard Disk 402 Bank number of image used in H-reader mode. 403 Bank 0 uses the host PC's hard disk image. 404 Driver Parameters in H-Reader Mode 405 Product revision level. 406 Header code 407 Device code 408 Release date 409 Communication Channel Setting 410 Setting that allocates the various communication channels to the CAFE interface(s). 411 Driver Timing Emulation Setting 412 Toggles use of driver timing emulation. 413 */ 414 415 } 416 417