/*---------------------------------------------------------------------------* Copyright (C) Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; using System.Net.NetworkInformation; using System.Text; namespace Nintendo.SDSG { public class NetworkInterfaceExplorer { public string ComputerName { get; private set; } public string DomainName { get; private set; } public IList ActiveNICs { get; private set; } public bool ConnectedToTheEther { get; private set; } public override string ToString() { StringBuilder sb = new StringBuilder(); foreach (NetworkInterface nic in ActiveNICs) { sb.AppendLine( GetIPv4Address(nic).ToString() ); } return sb.ToString(); } public NetworkInterfaceExplorer() { ReScan(); } public void ReScan() { IPGlobalProperties overall_props = IPGlobalProperties.GetIPGlobalProperties(); ComputerName = overall_props.HostName; DomainName = overall_props.DomainName; ConnectedToTheEther = NetworkInterface.GetIsNetworkAvailable(); ActiveNICs = _get_active_ethernet_adapters(); } public IPAddress GetIPv4Address(NetworkInterface nic) { foreach (var single_point_address in nic.GetIPProperties().UnicastAddresses) { if (single_point_address.Address.AddressFamily == AddressFamily.InterNetwork) { return single_point_address.Address; } } return IPAddress.None; } private IList _get_active_ethernet_adapters() { List rc = new List(); NetworkInterface[] all_network_cards = NetworkInterface.GetAllNetworkInterfaces(); foreach (var network_card in all_network_cards) { if (network_card.OperationalStatus != OperationalStatus.Up) { continue; } if (network_card.NetworkInterfaceType == NetworkInterfaceType.Loopback) continue; rc.Add(network_card); } return rc; } public static string GetPrettyMAC(byte[] mac_address) { return GetPrettyMAC(mac_address, 0); } public static string GetPrettyMAC(byte[] mac_address, int starting_index_in_buffer) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("{0:x2}:{0:x2}:{0:x2}:{0:x2}:{0:x2}:{0:x2}", mac_address[starting_index_in_buffer+0], mac_address[starting_index_in_buffer+1], mac_address[starting_index_in_buffer+2], mac_address[starting_index_in_buffer+3], mac_address[starting_index_in_buffer+4], mac_address[starting_index_in_buffer+5]); return sb.ToString(); } } public class MionIdentifier { public string Name {get; private set; } public string FieldProgrammableGateArrayVersion { get; private set; } public string FirmwareVersion { get; private set; } public string MACAddress { get; private set; } public byte Flags { get; private set; } public IPEndPoint NetworkAddress; private const int k_flags_idx = 0; private const int k_mac_addr_idx = 1; private const int k_name_len_idx = 7; private const int k_fpga_idx = 8; private const int k_fw_ver_idx = 12; private const int k_machine_name_idx = 16; internal static MionIdentifier TryCreate(byte[] broadcast_reciept, IPEndPoint location) { /* BYTE bFlags; // 0 BYTE MACAddr[6]; // 1 BYTE bMachineNameLength; // 7 BYTE FPGAVersion1; // 8 BYTE FPGAVersion2; // 9 BYTE FPGAVersion3; // 10 BYTE FPGAVersion4; // 11 BYTE FWVersion1; // 12 BYTE FWVersion2; // 13 BYTE FWVersion3; // 14 BYTE FWVersion4; // 15 char szMachineName[MAX_PATH]; // 16 */ if (broadcast_reciept[0] == (byte)MionUdp.MionCmdByte.Acknowledge) { return new MionIdentifier(broadcast_reciept, location); } return null; } private MionIdentifier(byte[] broadcast_reciept, IPEndPoint location) { Flags = broadcast_reciept[k_flags_idx]; MACAddress = NetworkInterfaceExplorer.GetPrettyMAC(broadcast_reciept, k_mac_addr_idx); Name = ASCIIEncoding.ASCII.GetString(broadcast_reciept, k_machine_name_idx, broadcast_reciept[k_name_len_idx]); NetworkAddress = location; FieldProgrammableGateArrayVersion = String.Format("{0}.{1}.{2}.{3}", broadcast_reciept[k_fpga_idx + 0], broadcast_reciept[k_fpga_idx + 1], broadcast_reciept[k_fpga_idx + 2], broadcast_reciept[k_fpga_idx + 3]); FirmwareVersion = String.Format("{0}.{1}.{2}.{3}", broadcast_reciept[k_fw_ver_idx + 0], broadcast_reciept[k_fw_ver_idx + 1], broadcast_reciept[k_fw_ver_idx + 2], broadcast_reciept[k_fw_ver_idx + 3]); } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.AppendFormat("{0,-16}: {3,-25} - FW {1} - FPGA {2}", NetworkAddress.Address, FirmwareVersion, FieldProgrammableGateArrayVersion, Name); return sb.ToString(); } } public class LocatedMions { internal LocatedMions() { } public NetworkInterfaceExplorer NetInfo { get; internal set; } public IList Mions { get; internal set; } } public class NetworkTuple { public byte[] Item1; public IPEndPoint Item2; public NetworkTuple(byte[] bytes, IPEndPoint endpoint) { Item1 = bytes; Item2 = endpoint; } } public class MionUdp { const string k_mion_string = "MULTI_I/O_NETWORK_BOARD"; const ushort k_mion_ctrl_port = 7974; const ushort k_mion_char_port = 7975; const ushort k_mion_bulk_port = 7976; internal enum MionCmdByte { //Search = 0x3f, //Broadcast = 0x21 AnnounceYourselves = 0x2a, Acknowledge = 0x20, } private static byte[] _create_buffer_for_announce_yourselves() { byte[] rc = new byte[25]; rc[0] = (byte)MionCmdByte.AnnounceYourselves; System.Text.ASCIIEncoding.ASCII.GetBytes(k_mion_string, 0, k_mion_string.Length, rc, 1); return (rc); } public static LocatedMions ScanLocalSubnetForMIONs() { NetworkInterfaceExplorer looker = new NetworkInterfaceExplorer(); LocatedMions rc = new LocatedMions(); rc.NetInfo = looker; if (looker.ConnectedToTheEther == false) { return rc; } IPAddress local_address = looker.GetIPv4Address(looker.ActiveNICs[0]); IPAddress broadcast_address; { string str_local_address = local_address.ToString(); string str_chopped_broadcast = str_local_address.Remove(str_local_address.LastIndexOf('.')); string str_final_broadcast = str_chopped_broadcast + ".255"; broadcast_address = IPAddress.Parse(str_final_broadcast); } IPEndPoint my_local_portcombo = new IPEndPoint(local_address, k_mion_ctrl_port); IPEndPoint target_destination_portcombo = new IPEndPoint(broadcast_address, k_mion_ctrl_port); byte[] msg_to_broadcast = _create_buffer_for_announce_yourselves(); Socket skBroadcaster = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); skBroadcaster.Bind(my_local_portcombo); skBroadcaster.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); rc.Mions = new List(); DateTime current_time = DateTime.Now; DateTime target_time = current_time.AddMilliseconds(10); skBroadcaster.SendTo(msg_to_broadcast, target_destination_portcombo); List replies = new List(); while (DateTime.Now < target_time) { int avail = skBroadcaster.Available; if (avail > 0) { EndPoint mion_portcombo = new IPEndPoint(IPAddress.Any, 0); byte[] mion_incoming_message = new byte[avail]; skBroadcaster.ReceiveFrom(mion_incoming_message, ref mion_portcombo); replies.Add(new NetworkTuple(mion_incoming_message, (IPEndPoint)mion_portcombo)); } } for (int i = 0; i < replies.Count; i++) { MionIdentifier a_mion = MionIdentifier.TryCreate(replies[i].Item1, replies[i].Item2); if (a_mion != null) rc.Mions.Add(a_mion); } skBroadcaster.Close(); return rc; } } /* #pragma once #include #define MION_CONTROL_PORT 7974 #define MION_KEYWORD "MULTI_I/O_NETWORK_BOARD" #define MION_SEARCH (BYTE)0x3f #define MION_ENUMERATE (BYTE)0x2a #define MION_ACK (BYTE)0x20 #define MION_BCAST (BYTE)0x21 #define MION_SEARCH_TIMEOUT 20000 #define FIRST_BYTE(n) (UINT32)(n&0x000000FF) #define SECOND_BYTE(n) (UINT32)((n&0x0000FF00) >> 8) #pragma pack(push, 1) typedef struct _mionsearchbridgeRequest { BYTE bFlags; char keyword[24]; BYTE bMachineNameLength; char szMachineName[MAX_PATH]; }MION_SEARCH_REQUEST, *PMION_SEARCH_REQUEST; typedef struct _mionglobalsearchbridgeRequest { BYTE bFlags; char keyword[24]; }MION_GLOBAL_SEARCH_REQUEST, *PMION_GLOBAL_SEARCH_REQUEST; typedef struct _mionsearchbridgeReply { BYTE bFlags; BYTE MACAddr[6]; BYTE bMachineNameLength; BYTE FPGAVersion1; BYTE FPGAVersion2; BYTE FPGAVersion3; BYTE FPGAVersion4; BYTE FWVersion1; BYTE FWVersion2; BYTE FWVersion3; BYTE FWVersion4; char szMachineName[MAX_PATH]; }MION_SEARCH_REPLY, *PMION_SEARCH_REPLY; #pragma pack(pop) */ /* Table 4-25 List of Settings Item Name Description Machine Name Name consisting of ASCII characters. (Up to 256 characters, including the terminator.) MAC Address MAC address allocated to MION. (Reference only.) Language Setting Specify Automatic, Japanese, or English. If you specify Automatic, it references the header information in the browser. Settings for automatically getting IP address Toggle use of DHCP / Auto IP UPnP [1] IP Address Manually-set IP address. Subnet Mask Manually-set subnet mask. Default Gateway Manually-set IP address of default gateway. Settings to automatically get DNS server address Toggle use of DHCP. Primary DNS Server Manually-set IP address of primary DNS server. Secondary DNS Server Manually-set IP address of secondary DNS server. Ethernet Frame Size Select from 1500 bytes, 3000 bytes, 4000 bytes, 5000 bytes, 6000 bytes, 7000 bytes, 8000 bytes, and 9700 bytes.[2] Default Host PC IP Address IP address of PC that serves as ATAPI emulator host. ATAPI Emulator Port Number Sets port number to use for communication with ATAPI Emulator interface. (Default: 7974) FIFO1 Port Number Sets port number to use for communication with FIFO1. (Default: 7975) FIFO2 Port Number Sets port number to use for communication with FIFO2. (Default: 7976) Size of Buffer for FIFO1 Interface Select from 4KB, 32KB, 128KB, 256KB, 512KB, 1MB, 2MB, and 4MB. (Default: 4KB) Size of Buffer for FIFO2 Interface Select from 128KB, 256KB, 512KB, 1MB, 2MB, 4MB, 8MB, and 16MB. (Default: 128KB) Hard Disk Bank Size Setting Select from 2GB, 5GB, 10GB, 12GB, 15GB, 18GB, 21GB, and 25GB. (Default: 25GB) Current Bank Number of Hard Disk Bank number of image used in H-reader mode. Bank 0 uses the host PC's hard disk image. Driver Parameters in H-Reader Mode Product revision level. Header code Device code Release date Communication Channel Setting Setting that allocates the various communication channels to the CAFE interface(s). Driver Timing Emulation Setting Toggles use of driver timing emulation. */ }