/*---------------------------------------------------------------------------* Copyright 2010-2012 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.Diagnostics; using System.Net.Sockets; using System.IO; using System.Net; using System.Collections.Generic; using System.Threading; using System.Text; namespace CafeX { /// /// This class encapsulates the functionality of the dkt.exe tool used by CafeX. /// static class dkt { static string cygwin_dkt_exe_path = "\"" + Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\dkt.exe" + "\""; private static string GetExeName() { string dkt_or_temp_exe_path; if (FileUtil.RunningFromCygwin) { // take the monitor from cygwin dkt_or_temp_exe_path = cygwin_dkt_exe_path; } else { dkt_or_temp_exe_path = FileUtil.ExpandExecutable(CafeX.Properties.Resources.win_dkt, "win_dkt.exe"); } return dkt_or_temp_exe_path; } internal static int FlushOutputBuffer() { #if DEBUG Log.WriteLine("dkt.FlushOutputBuffer started -> calls FlushOuputBuffer( 1 second)."); #endif return dkt.FlushOutputBuffer(1); } internal static int FlushOutputBuffer(uint seconds) { string strSeconds = seconds.ToString(); #if DEBUG Log.WriteLine("dkt.FlushOutputBuffer(" + strSeconds + ") started."); #endif return ProcessExecutor.DoProcess(GetExeName(), "-d 40 " + strSeconds); } } /// /// This class encapsulates the functionality of the PCFSServer used by CafeX. /// static class PCFSServer { static string exe_path = null; static string output_log = String.Empty; private static void setExePath() { string testInMionBridge = Environment.GetEnvironmentVariable("MION_BRIDGE_TOOLS") + "\\pcfs\\PCFSServer.exe"; if (File.Exists(testInMionBridge)) { exe_path = testInMionBridge; } else { exe_path = Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\PCFSServer.exe"; } FileUtil.AddQuotes(ref exe_path); } internal static int Shutdown() { #if DEBUG Log.WriteLine("PCFSServer.Shutdown started."); #endif setExePath(); return ProcessExecutor.DoProcess(exe_path, "-q"); } internal static int Start(string parameters, string mapping, string log) { #if DEBUG Log.WriteLine("PCFSServer.Start started. parameters=" + parameters + ", mapping=" + mapping + ", log=" + log); #endif setExePath(); output_log = log; return ProcessExecutor.StartProcess_RedirectOutput(exe_path, "-r 100 " + parameters + " " + Environment.GetEnvironmentVariable("PCFS_HEADLESS_EMUL") + " " + mapping, output_callback, false); } static void output_callback(Object sender, DataReceivedEventArgs line) { #if DEBUG Log.WriteLine("PCFSServer.output_callback started."); #endif setExePath(); if (output_log != "/dev/null") { try { FileStream s = new FileStream(output_log, FileMode.Append, FileAccess.Write); StreamWriter w = new StreamWriter(s); w.Write(line.Data); w.Flush(); w.Close(); } catch (IOException ex) { Console.WriteLine("cafex [PCFSServer]: Caught exception while writing stdout to '{0}':", output_log); Console.WriteLine(" {0}", ex.Message); // Prevent future log file writes output_log = "/dev/null"; } } } } /// /// This class encapsulates the functionality of the checkbridge tool used by CafeX. /// static class checkbridgename { static string exe_path = "\"" + Environment.GetEnvironmentVariable("MION_BRIDGE_TOOLS") + "\\checkbridgename.exe" + "\""; internal static int CheckName(ref string output) { #if DEBUG Log.WriteLine("checkbridgename.CheckName started."); #endif string args = string.Format("\"{0}\" -ip {1}", Environment.GetEnvironmentVariable("BRIDGE_CURRENT_NAME"), Environment.GetEnvironmentVariable("BRIDGE_CURRENT_IP_ADDRESS")); int returnVal = ProcessExecutor.DoProcess_GetOutput(exe_path, args, out output); return returnVal; } internal static int CheckName() { string output = string.Empty; return CheckName(ref output); } internal static int CheckName_IPOnly() { #if DEBUG Log.WriteLine("checkbridgename.CheckName_IPOnly started."); #endif int returnVal; string output = string.Empty; returnVal = ProcessExecutor.DoProcess_GetOutput(exe_path, "-s -ip " + Environment.GetEnvironmentVariable("BRIDGE_CURRENT_IP_ADDRESS"), out output); Console.Write(output); return returnVal; } } /// /// This class encapsulates the functionality of the toucanreset tool used by CafeX. /// static class ToucanReset { static string exe_path = "\"" + Environment.GetEnvironmentVariable("MION_BRIDGE_TOOLS") + "\\ToucanReset.exe" + "\""; internal static int Stop() { #if DEBUG Log.WriteLine("ToucanReset.Stop started."); #endif return ProcessExecutor.DoProcess(exe_path, "-stop"); } internal static int Reset() { #if DEBUG Log.WriteLine("ToucanReset.Reset started."); #endif return ProcessExecutor.DoProcess(exe_path, Environment.GetEnvironmentVariable("HOSTSTOP_RESET_OPTION")); } } /// /// This class encapsulates the functionality of the fsemul tool used by CafeX. /// static class FSEmul { static string exe_path = "\"" + Environment.GetEnvironmentVariable("MION_BRIDGE_TOOLS") + "\\FSEmul.exe" + "\""; internal static int makemine() { #if DEBUG Log.WriteLine("FSEmul.makemine started."); #endif int returnVal; string output = string.Empty; returnVal = ProcessExecutor.DoProcess_GetOutput(exe_path, "-ip " + Environment.GetEnvironmentVariable("BRIDGE_CURRENT_IP_ADDRESS") + " -makemine", out output); Console.Write(output); return returnVal; } internal static int FW_SW_Version(string ip, out string fw_ver, out string sw_ver) { #if DEBUG Log.WriteLine("FSEmul.FW_SW_Version started."); #endif string arguments = (ip != null) ? "-ver -ip " + ip : "-ver"; // Remember and clear the TOUCAN_VERBOSE variable as this causes the version to be parsed as blank string localTOUCAN_VERBOSE = Environment.GetEnvironmentVariable("TOUCAN_VERBOSE"); Environment.SetEnvironmentVariable("TOUCAN_VERBOSE", ""); string output = string.Empty; int ret = ProcessExecutor.DoProcess_GetOutput(exe_path, arguments, out output); // Restore the TOUCAN_VERBOSE variable if (!string.IsNullOrEmpty(localTOUCAN_VERBOSE)) { Environment.SetEnvironmentVariable("TOUCAN_VERBOSE", localTOUCAN_VERBOSE); } if (ret != 0) { Console.WriteLine("FSEmul failed: Couldn't get firmware versions"); fw_ver = string.Empty; sw_ver = string.Empty; return ret; } char[] delimiters = new char[3]; delimiters[0] = ' '; delimiters[1] = '\r'; delimiters[2] = '\n'; string[] split = output.Split(delimiters); fw_ver = split[3]; sw_ver = split[8]; return ret; } internal static int boot_mode_detect(string ip, out string boot_mode) { #if DEBUG Log.WriteLine("FSEmul.boot_mode_detect started."); #endif if (string.IsNullOrEmpty(ip)) { boot_mode = "UNKNOWN"; return 1; } string arguments = "-ip " + ip + " -modedetect"; // Remember and clear the TOUCAN_VERBOSE variable as this causes the version to be parsed as blank string localTOUCAN_VERBOSE = Environment.GetEnvironmentVariable("TOUCAN_VERBOSE"); Environment.SetEnvironmentVariable("TOUCAN_VERBOSE", ""); string output = string.Empty; int ret = ProcessExecutor.DoProcess_GetOutput(exe_path, arguments, out output); // Restore the TOUCAN_VERBOSE variable if (!string.IsNullOrEmpty(localTOUCAN_VERBOSE)) { Environment.SetEnvironmentVariable("TOUCAN_VERBOSE", localTOUCAN_VERBOSE); } if (ret != 0) { Console.WriteLine("FSEmul failed: Couldn't detect boot mode!"); boot_mode = "UNKNOWN"; return ret; } boot_mode = output.Trim(); return 0; } internal static int start(string arguments, string fsemul_params) { #if DEBUG Log.WriteLine("FSEmul.start started."); #endif DataReceivedEventHandler handler = new DataReceivedEventHandler((sender, args) => { if (args != null && args.Data != null) { Console.WriteLine(args.Data); // If FSEmul throws, suggest using cafestop -makemine if (args.Data.ToString().Contains("Bridge is being used by the PC with IP Address")) { Console.WriteLine("\nTry using 'cafex stop -makemine' to take control of the Bridge."); } } }); return ProcessExecutor.StartProcess_RedirectOutput(exe_path, arguments + " " + fsemul_params, handler, false); } } /// /// This class encapsulates the functionality of the mionbutton tool used by CafeX. /// static class MionButton { static string exe_path = "\"" + Environment.GetEnvironmentVariable("MION_BRIDGE_TOOLS") + "\\MionButton.exe" + "\""; internal static int rsthold(string[] args) { #if DEBUG Log.WriteLine("MionButton.rsthold started."); #endif string output = string.Empty; int returnVal; string arg_string = StringCombiner.MakeDelimitedString(args, ' '); returnVal = ProcessExecutor.DoProcess_GetOutput(exe_path, "-ip " + Environment.GetEnvironmentVariable("BRIDGE_CURRENT_IP_ADDRESS") + " -rsthold " + arg_string, out output); // Print output to console Console.Write(output); return returnVal; } internal static int forceOff1(string[] args) { #if DEBUG Log.WriteLine("mionButton.forceOff1 started."); #endif string output = string.Empty; int returnVal; string arg_string = StringCombiner.MakeDelimitedString(args, ' '); returnVal = ProcessExecutor.DoProcess_GetOutput(exe_path, "-ip " + Environment.GetEnvironmentVariable("BRIDGE_CURRENT_IP_ADDRESS") + " -forceOff1 " + arg_string, out output); // Print output to console Console.Write(output); return returnVal; } internal static int init_shutdown_w_FOFF2(string[] args) { #if DEBUG Log.WriteLine("MionButton.init_shutdown_w_FOFF2 started."); #endif string output = string.Empty; int returnVal; string arg_string = StringCombiner.MakeDelimitedString(args, ' '); returnVal = ProcessExecutor.DoProcess_GetOutput(exe_path, "-ip " + Environment.GetEnvironmentVariable("BRIDGE_CURRENT_IP_ADDRESS") + " -init_shutdown_w_FOFF2 60000 " + arg_string, out output); // Print output to console Console.Write(output); return returnVal; } internal static int forceOff2_off_single_cgi(string[] args) { #if DEBUG Log.WriteLine("MionButton.forceOff2_off_single_cgi started."); #endif string output = string.Empty; int returnVal; string arg_string = StringCombiner.MakeDelimitedString(args, ' '); returnVal = ProcessExecutor.DoProcess_GetOutput(exe_path, "-ip " + Environment.GetEnvironmentVariable("BRIDGE_CURRENT_IP_ADDRESS") + " -forceOff2_off_single_cgi " + arg_string, out output); // Print output to console Console.Write(output); return returnVal; } } /// /// This class encapsulates the functionality of the miontelnet tool used by CafeX. /// static class miontelnet { static string exe_path = "\"" + Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\miontelnet.exe" + "\""; internal static int Reboot(out string output) { #if DEBUG Log.WriteLine("miontelnet.Reboot started."); #endif return ProcessExecutor.DoProcess_GetOutput(exe_path, "-reboot", out output); } internal static int Run(out string output) { #if DEBUG Log.WriteLine("miontelnet.Run started."); #endif return ProcessExecutor.DoProcess_GetOutput(exe_path, null, out output); } } /// /// This class encapsulates the functionality of the mionps tool used by CafeX. /// static class mionps { static string exe_path = "\"" + Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\mionps.exe" + "\""; private static readonly int MIONPS_TIMEOUT_MS = 30000; // 30 seconds internal static string Run(string arguments) { #if DEBUG Log.WriteLine("mionps.Run started."); #endif string output = string.Empty; int returnVal = ProcessExecutor.DoProcess_GetOutput(exe_path, arguments, true, MIONPS_TIMEOUT_MS, out output); // Currently, all the calls to mionps are assuming a single line without CRLF. // If that changes, removing CRLF below will need to be removed and calls to RUN revisited. output = output.Replace("\r\n", ""); // Error checking for mionps if (returnVal != 0) { Console.WriteLine("cafex : Warning! mionps tool returned code {0}.", returnVal); Console.WriteLine("mionps stdout and stderr received:"); Console.WriteLine(output); } return output; } } /// /// This class encapsulates the functionality of the mionurl tool used by CafeX. /// static class mionurl { static string exe_path = "\"" + Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\mionurl.exe" + "\""; private static readonly int MIONURL_TIMEOUT_MS = 30000; // 30 seconds internal static int Run(string arguments) { #if DEBUG Log.WriteLine("mionurl.Run started."); #endif string output = string.Empty; int returnVal = ProcessExecutor.DoProcess_GetOutput(exe_path, arguments, true, MIONURL_TIMEOUT_MS, out output); // Currently, all the calls to mionurl are assuming a single line without CRLF. // If that changes, removing CRLF below will need to be removed and calls to RUN revisited. output = output.Replace("\r\n", ""); // Error checking for mionurl if (returnVal != 0) { Console.WriteLine("cafex : Warning! mionurl tool returned code {0}.", returnVal); Console.WriteLine("mionurl stdout and stderr received:"); Console.WriteLine(output); } return returnVal; } } /// /// This class encapsulates the functionality of the sessionmanager tool used by CafeX. /// static class SessionManagerUtil { static string exe_path = "\"" + Environment.GetEnvironmentVariable("MION_BRIDGE_TOOLS") + "\\SessionManagerUtil.exe" + "\""; internal static int GetSessionInfo(out string output) { #if DEBUG Log.WriteLine("SessionManagerUtil.GetSessionInfo started."); #endif return ProcessExecutor.DoProcess_GetOutput(exe_path, "-p NAME DEBUG_OUT DEBUG_CONTROL HIO_OUT LAUNCH_CTRL NET_MANAGE PCFS_SATA", out output); } } /// /// This class encapsulates the functionality of the devkitmsg tool used by CafeX. /// static class devkitmsg { internal static string CAFEX_RECOVER_TEST = Environment.GetEnvironmentVariable("CAFEX_RECOVER_TEST"); static string exe_path = "\"" + Environment.GetEnvironmentVariable("MION_BRIDGE_TOOLS") + "\\devkitmsg.exe" + "\""; internal static int help(int timeout) { #if DEBUG Log.WriteLine("devkitmsg.help started with timeout = " + timeout.ToString()); #endif int returnVal = 2; Console.WriteLine("cafex: Probing if COS is ready by sending devkit help msg:"); string msg = "\"help\" -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT"); DateTime maxTime = DateTime.Now.AddMilliseconds((double)timeout); do { returnVal = ProcessExecutor.DoProcess(exe_path, msg); if (returnVal == 0) { break; } System.Threading.Thread.Sleep(Program.RETRY_TIMESPAN); // wait for a second. } while (maxTime.CompareTo(DateTime.Now) > 0); #if DEBUG Log.WriteLine("devkitmsg.help returnVal = " + returnVal.ToString()); #endif return returnVal; } internal static int CosFlags(string ppc_os_flags) { #if DEBUG Log.WriteLine("devkitmsg.CosFlags started."); #endif return ProcessExecutor.DoProcess(exe_path, "\"cos_flags " + ppc_os_flags + "\" -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int title_softlaunch_with_hint(string os, string tid, string hint, string port) { #if DEBUG Log.WriteLine("devkitmsg.title_softlaunch_with_hint started."); #endif return ProcessExecutor.DoProcess(exe_path, "\"title_softlaunch " + os + " " + tid + " " + hint + "\" -v -p " + port); } internal static int title_softlaunch(string os, string tid, string port) { #if DEBUG Log.WriteLine("devkitmsg.title_softlaunch started."); #endif DataReceivedEventHandler callback = (sender, e) => { if (e != null && e.Data != null) { Console.WriteLine(e.Data); } }; return ProcessExecutor.StartProcess_RedirectOutput(exe_path, "\"title_softlaunch " + os + " " + tid + "\" -v -p " + port, callback, true); } internal static int recover() { #if DEBUG Log.WriteLine("devkitmsg.recover started."); #endif if (CAFEX_RECOVER_TEST == "1") { Console.WriteLine("devkitmsg_cmd: recover -v -p "); return 0; } return ProcessExecutor.DoProcess(exe_path, "recover -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int update_pcfs() { #if DEBUG Log.WriteLine("dvkitmsg.update_pcfs started."); #endif if (CAFEX_RECOVER_TEST == "1") { Console.WriteLine("devkitmsg_cmd: update /vol/storage_hfiomlc01/sys/update/pcfs -v -p "); return 0; } return ProcessExecutor.DoProcess(exe_path, "\"update /vol/storage_hfiomlc01/sys/update/pcfs\" -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int update_reflash() { #if DEBUG Log.WriteLine("devkitmsg.update_reflash started."); #endif if (CAFEX_RECOVER_TEST == "1") { Console.WriteLine("devkitmsg_cmd: reflash /vol/storage_hfiomlc01/sys/update/nand -v -p "); return 0; } return ProcessExecutor.DoProcess(exe_path, "\"reflash /vol/storage_hfiomlc01/sys/update/nand\" -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int update_nand() { #if DEBUG Log.WriteLine("devkitmsg.update_nand started."); #endif if (CAFEX_RECOVER_TEST == "1") { Console.WriteLine("devkitmsg_cmd: update /vol/storage_hfiomlc01/sys/update/nand -v -p "); return 0; } return ProcessExecutor.DoProcess(exe_path, "\"update /vol/storage_hfiomlc01/sys/update/nand\" -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int update(string update_path) { #if DEBUG Log.WriteLine("devkitmsg.update started."); #endif if (string.IsNullOrEmpty(update_path)) { return 1; } if (CAFEX_RECOVER_TEST == "1") { Console.WriteLine("devkitmsg_cmd: update " + update_path + " -v -p "); return 0; } return ProcessExecutor.DoProcess(exe_path, "\"update " + update_path + "\" -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int reflash(string reflash_path) { #if DEBUG Log.WriteLine("devkitmsg.reflash started."); #endif if (string.IsNullOrEmpty(reflash_path)) { return 1; } if (CAFEX_RECOVER_TEST == "1") { Console.WriteLine("devkitmsg_cmd: reflash " + reflash_path + " -v -p "); return 0; } return ProcessExecutor.DoProcess(exe_path, "\"reflash " + reflash_path + "\" -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int clr_usrdata() { #if DEBUG Log.WriteLine("devkitmsg.clr_usrdata started."); #endif if (CAFEX_RECOVER_TEST == "1") { Console.WriteLine("devkitmsg_cmd: clr_usrdata -v -p "); return 0; } return ProcessExecutor.DoProcess(exe_path, "clr_usrdata -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int sys_mode_dev() { #if DEBUG Log.WriteLine("devkitmsg.sys_mode_dev started."); #endif return ProcessExecutor.DoProcess(exe_path, "\"sys_mode 1\" -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int sys_mode_prod() { #if DEBUG Log.WriteLine("devkitmsg.sys_mode_prod started."); #endif return ProcessExecutor.DoProcess(exe_path, "\"sys_mode 0\" -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int sys_mode_test() { #if DEBUG Log.WriteLine("devkitmsg.sys_mode_test started."); #endif return ProcessExecutor.DoProcess(exe_path, "\"sys_mode 2\" -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } internal static int standby_en(int value) { #if DEBUG Log.WriteLine("devkitmsg.standby_en " + value); #endif return ProcessExecutor.DoProcess(exe_path, " 'standby_en 1' -v -p " + Environment.GetEnvironmentVariable("SESSION_LAUNCH_CTRL_PORT")); } } static class cosdebug { #if TIMER public static PerfTimer cosdebugSetupTime = new PerfTimer("cosdebugSetupTime"); #endif #if false private static Thread retry_thread = null; private static ManualResetEvent stop_event = null; private struct LaunchRetryParams { public int port; public string TID_HI; public string TID_LO; public int retries; public int timeout; public int delay; } #endif internal static void StreamDiscard(Stream stream) { try { int b; stream.ReadTimeout = 500; #if DEBUG Console.Write("cafex: cosdebug.launch discarding:"); #endif while ((b = stream.ReadByte()) != -1) { #if DEBUG Console.Write(" {0:X2}", b); #endif } } catch (IOException) { // Eat this exception. The timeout just expired } finally { #if DEBUG Console.WriteLine(); #endif } } #if false private static void launch_retry_thread(object data) { LaunchRetryParams lrparams = (LaunchRetryParams)data; #if DEBUG Log.WriteLine("cosdebug.launch_retry_thread started."); Log.WriteLine("Params:"); Log.WriteLine(string.Format(" port: {0}.", lrparams.port)); Log.WriteLine(string.Format(" TID_HI: {0}.", lrparams.TID_HI)); Log.WriteLine(string.Format(" TID_LO: {0}.", lrparams.TID_LO)); Log.WriteLine(string.Format(" retries: {0}.", lrparams.retries)); Log.WriteLine(string.Format(" timeout: {0}.", lrparams.timeout)); #endif cattoucan.ClearNotifications(); ManualResetEvent[] evtHandle = new ManualResetEvent[3]; evtHandle[0] = new ManualResetEvent(false); cattoucan.AddNotification(Nintendo.SDSG.CatToucan.Terms.KI_PIREPARE_TITLE_ASYNC, evtHandle[0]); evtHandle[1] = new ManualResetEvent(false); cattoucan.AddNotification("System busy, try again", evtHandle[1]); evtHandle[2] = stop_event; for (int retry = 0; retry < lrparams.retries; retry++) { launch(lrparams.port, lrparams.TID_HI, lrparams.TID_LO); long start = DateTime.Now.Ticks; #if DEBUG Log.WriteLine(string.Format("cosdebug.launch_retry_thread: waiting on handles {0} and {1}.", evtHandle[0].Handle, evtHandle[1].Handle)); #endif switch (WaitHandle.WaitAny(evtHandle, lrparams.timeout)) { case 0: // Got the success message and we are done Log.WriteLineRaw("cafex: Got successful title fast launch message."); #if DEBUG Log.WriteLine(string.Format("cosdebug.launch_retry_thread: waited {0}mS.", TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalMilliseconds)); #endif evtHandle[0].Reset(); return; case 1: // Got the retry, so we continue Log.WriteLineRaw(string.Format("cafex: Got system busy message after fast launch, waiting {0}mS and retrying...", lrparams.delay)); #if DEBUG Log.WriteLine(string.Format("cosdebug.launch_retry_thread: waited {0}mS.", TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalMilliseconds)); Log.WriteLine(string.Format(" : delaying {0}mS.", lrparams.delay)); #endif evtHandle[1].Reset(); Thread.Sleep(lrparams.delay); break; case 2: #if DEBUG Log.WriteLine("cosdebug.retry_launch_thread: Got stop event, returning."); #endif return; case WaitHandle.WaitTimeout: Log.WriteLineRaw(string.Format("cafex: Fastlaunch timeout of {0}mS exceeded waiting for title to start, exiting.", lrparams.timeout)); Environment.Exit((int)CAFEX_ERROR.RUN_FASTLAUNCH_FAILED); return; } } // Exhausted all of our tries Log.WriteLineRaw(string .Format("cafex: Unable to fastlaunch title after {0} attempts, exiting.", lrparams.retries)); Environment.Exit((int)CAFEX_ERROR.RUN_FASTLAUNCH_FAILED); } internal static void launch_retry(int port, string TID_HI, string TID_LO, int retries, int timeout, int delay) { #if DEBUG Log.WriteLine("cosdebug.launch_retry started."); #endif LaunchRetryParams lrparams = new LaunchRetryParams(); lrparams.port = port; lrparams.TID_HI = TID_HI; lrparams.TID_LO = TID_LO; lrparams.retries = retries; lrparams.timeout = timeout; lrparams.delay = delay; retry_thread = new Thread(cosdebug.launch_retry_thread); stop_event = new ManualResetEvent(false); retry_thread.Start(lrparams); #if DEBUG Log.WriteLine("cosdebug.launch_retry exited."); #endif } public static void stop_retry(int timeout) { if (retry_thread != null) { stop_event.Set(); retry_thread.Join(timeout); } } #endif internal static int launch(int port, string TID_HI, string TID_LO) { #if DEBUG Log.WriteLine("cosdebug.launch started."); #endif try { TcpClient client = new TcpClient("localhost", port); NetworkStream stream = client.GetStream(); // Discard any input if anything is waiting after connect. COS sends some prompts after connect. StreamDiscard(stream); string message = string.Format("\rcos launch 0x{0} 0x{1}\r", TID_HI, TID_LO); Log.WriteLineRaw(string.Format("cafex: sending '{0}' to the devkit using port {1}...", message.Trim(), port)); byte[] data = System.Text.Encoding.ASCII.GetBytes(message); #if DEBUG Console.Write("cafex: cosdebug.launch write ({0} bytes):", data.Length); for (int i = 0; i < data.Length; i++) { Console.Write(" 0x{0:X2}", data[i]); } Console.WriteLine(); #endif stream.WriteTimeout = 5000; stream.Write(data, 0, data.Length); // Discard any input stream if anything is sent after the write. StreamDiscard(stream); client.Close(); } catch (InvalidOperationException e) { Log.WriteLine(string.Format("cafex: cosdebug.launch: InvalidOperationException: {0}", e)); } catch (ArgumentNullException e) { Log.WriteLine(string.Format("cafex: cosdebug.launch: ArgumentNullException: {0}", e)); } catch (SocketException e) { Log.WriteLine(string.Format("cafex: cosdebug.launch: SocketException: {0}", e)); } catch (IOException e) { Log.WriteLine(string.Format("cafex: cosdebug.launch: IOException: {0}", e)); } return 0; } internal static bool try_launch(string TID, int index) { int retries = Convert.ToInt32(Program.CAFERUN_OPTION_FASTLAUNCH_RETRIES.value); int timeout = Convert.ToInt32(Program.CAFERUN_OPTION_FASTLAUNCH_TIMEOUT.value); int delay = Convert.ToInt32(Program.CAFERUN_OPTION_FASTLAUNCH_DELAY.value); int port = Convert.ToInt32(Program.SESSION_NET_MANAGE_PORT.value); string TID_HI = TID.Substring(index, 8); string TID_LO = TID.Substring(index + 8, 8); if (Program.CAFE_PROFILE.value != null && Program.CAFE_PROFILE.value == "1") { CafeXEventtLog.Instance.WriteToEventLog(562, string.Format("[{0}] [BEGIN] [CafeX] System is doing FAST RELAUNCH", DateTime.Now.ToString("HH:mm:ss:fff"))); } cattoucan.BeginTitleFastSync(); for (index = 0; index < retries; ++index) { cattoucan.PrepareFastLaunch(delay); launch(port, TID_HI, TID_LO); if (cattoucan.SyncWithTitle(timeout, true)) { return true; } #if DEBUG Log.WriteLine("Retrying fast launch..."); #endif } cattoucan.FinishSync(true); return false; } internal static bool ParseReceivedMessage(string sMessage, string sParseStr, string sArgs) { string[] msgArray = sMessage.Split(' '); for (int i = 0; i < msgArray.Length; i++) { string str = msgArray[i]; if ((str.CompareTo(sParseStr) == 0) && ((i + 1) < msgArray.Length) && (msgArray[i + 1].CompareTo(sArgs) == 0)) return true; } return false; } internal static string SendCOSCommandAndRecvReply(int iPort, string sCmd, string sArgs, int iRetries, int iTimeout, int iDelay) { StringBuilder completeMessage = new StringBuilder(); TcpClient client = null; NetworkStream stream = null; #if DEBUG Log.WriteLine("cosdebug." + sCmd + " started."); #endif try { #if TIMER Log.WriteLine("new TcpClient start"); cosdebugSetupTime.Report(); #endif client = new TcpClient("localhost", iPort); #if TIMER Log.WriteLine("new TcpClient end"); cosdebugSetupTime.Report(); #endif stream = client.GetStream(); // Discard any input if anything is waiting after connect. COS sends some prompts after connect. //StreamDiscard(stream); string message = string.Format("{0} {1}\r", sCmd, sArgs); Log.WriteLineRaw(string.Format("cafex: sending '{0}' to the devkit using port {1}...", message.Trim(), iPort)); byte[] data = System.Text.Encoding.ASCII.GetBytes(message); #if DEBUG Console.Write("cafex: cosdebug.{0} write ({1} bytes):", sCmd, data.Length); for (int i = 0; i < data.Length; i++) { Console.Write(" 0x{0:X2}", data[i]); } Console.WriteLine(); #endif stream.WriteTimeout = iTimeout; stream.ReadTimeout = iTimeout; stream.Write(data, 0, data.Length); Thread.Sleep(iDelay); if (stream.CanRead) { byte[] readBuffer = new byte[4096]; int readIndex = 0; int numberOfBytesRead = 0; int count = 0; while (!stream.DataAvailable) { if (count == iRetries) { break; } Thread.Sleep(iDelay); count++; } if (count <= iRetries || stream.DataAvailable) { // Incoming message may be larger than the buffer size. while (stream.DataAvailable) { numberOfBytesRead = stream.Read(readBuffer, readIndex, readBuffer.Length); completeMessage.AppendFormat("{0}", Encoding.ASCII.GetString(readBuffer, 0, numberOfBytesRead)); readIndex += numberOfBytesRead; Thread.Sleep(200); } #if DEBUG Console.Write("cafex: cosdebug.{0} read ({1}):", sCmd, completeMessage); Console.WriteLine(); #endif } } } catch (InvalidOperationException e) { Log.WriteLine(string.Format("cafex: cosdebug.{0}: InvalidOperationException: {1}", sCmd, e)); } catch (ArgumentNullException e) { Log.WriteLine(string.Format("cafex: cosdebug.{0}: ArgumentNullException: {1}", sCmd, e)); } catch (SocketException e) { Log.WriteLine(string.Format("cafex: cosdebug.{0}: SocketException: {1}", sCmd, e)); } catch (IOException e) { Log.WriteLine(string.Format("cafex: cosdebug.{0}: IOException: {1}", sCmd, e)); } catch (Exception e) { Log.WriteLine(string.Format("cafex: cosdebug.{0}: Exception: {1}", sCmd, e)); } finally { if (stream != null) { stream.Close(); } if (client != null) { client.Close(); } } return completeMessage.ToString(); } #if false internal static string SendCOSCommandAndRecvReply(int iPort, string sCmd, string sArgs, int iRetries, int iTimeout, int iDelay) { #if DEBUG Log.WriteLine("cosdebug." + sCmd + " started."); #endif Socket skt = null; StringBuilder completeMessage = new StringBuilder(); try { IPAddress[] ipAddrList = Dns.GetHostEntry("localhost").AddressList; skt = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); skt.Connect(ipAddrList, iPort); if (skt.Connected) { string message = string.Format("{0} {1}\r", sCmd, sArgs); Log.WriteLineRaw(string.Format("cafex: sending '{0}' to the devkit using port {1}...", message.Trim(), iPort)); byte[] bytesSent = System.Text.Encoding.ASCII.GetBytes(message); #if DEBUG Console.Write("cafex: cosdebug.{0} write ({1} bytes):", sCmd, bytesSent.Length); for (int i = 0; i < bytesSent.Length; i++) { Console.Write(" 0x{0:X2}", bytesSent[i]); } Console.WriteLine(); #endif skt.SendTimeout = iTimeout; skt.ReceiveTimeout = iTimeout; skt.Send(bytesSent, bytesSent.Length, 0); Thread.Sleep(1000); byte[] bytesRead = new byte[4096]; int numberOfBytesRead = 0; numberOfBytesRead = skt.Receive(bytesRead, bytesRead.Length, 0); completeMessage.AppendFormat("{0}", Encoding.ASCII.GetString(bytesRead, 0, numberOfBytesRead)); #if DEBUG Console.Write("cafex: cosdebug.{0} read ({1}):", sCmd, completeMessage); Console.WriteLine(); #endif } } catch (InvalidOperationException e) { Log.WriteLine(string.Format("cafex: cosdebug.{0}: InvalidOperationException: {1}", sCmd, e)); } catch (ArgumentNullException e) { Log.WriteLine(string.Format("cafex: cosdebug.{0}: ArgumentNullException: {1}", sCmd, e)); } catch (SocketException e) { Log.WriteLine(string.Format("cafex: cosdebug.{0}: SocketException: {1}", sCmd, e)); } catch (IOException e) { Log.WriteLine(string.Format("cafex: cosdebug.{0}: IOException: {1}", sCmd, e)); } finally { if (skt != null) { skt.Close(); } } return completeMessage.ToString(); } #endif internal static string RecvReply(int iPort, int iTimeout) { try { TcpClient client = new TcpClient("localhost", iPort); NetworkStream stream = client.GetStream(); if (stream.CanRead) { byte[] readBuffer = new byte[4096]; StringBuilder completeMessage = new StringBuilder(); int numberOfBytesRead = 0; int count = 10; while (!stream.DataAvailable) { if (count == 0) { break; } Thread.Sleep(10); count--; } if (count > 0 || stream.DataAvailable) { // Incoming message may be larger than the buffer size. do { numberOfBytesRead = stream.Read(readBuffer, 0, readBuffer.Length); completeMessage.AppendFormat("{0}", Encoding.ASCII.GetString(readBuffer, 0, numberOfBytesRead)); } while (stream.DataAvailable); #if DEBUG Console.Write("cafex: cosdebug.RecvReply read ({0}):", completeMessage); Console.WriteLine(); #endif } client.Close(); return completeMessage.ToString(); } client.Close(); return string.Empty; } catch (InvalidOperationException e) { Log.WriteLine(string.Format("cafex: cosdebug.RecvReply: InvalidOperationException: {0}", e)); } catch (ArgumentNullException e) { Log.WriteLine(string.Format("cafex: cosdebug.RecvReply: ArgumentNullException: {0}", e)); } catch (SocketException e) { Log.WriteLine(string.Format("cafex: cosdebug.RecvReply: SocketException: {0}", e)); } catch (IOException e) { Log.WriteLine(string.Format("cafex: cosdebug.RecvReply: IOException: {0}", e)); } return string.Empty; } internal static bool SendKillRestartAndResponse(int iPort, int iRetries, int iTimeout, int iDelay) { string args = Convert.ToString((int)DateTime.Now.Ticks); #if TIMER Log.WriteLine("SendCOSCommandAndRecvReply start"); cosdebugSetupTime.Reset(); cosdebugSetupTime.Start(); #endif string reply = SendCOSCommandAndRecvReply(iPort, "cos killrestart", args, iRetries, iTimeout, iDelay); #if TIMER Log.WriteLine("SendCOSCommandAndRecvReply end"); cosdebugSetupTime.Stop(); #endif if (string.IsNullOrEmpty(reply)) { return false; } bool bFoundAck = ParseReceivedMessage(reply, "kill_ack", args); bool bFoundDone = ParseReceivedMessage(reply, "kill_done", args); if (bFoundAck && bFoundDone) return true; //This happens rarely if (bFoundAck && !bFoundDone) { Thread.Sleep(iDelay); reply = RecvReply(iPort, iDelay); if (string.IsNullOrEmpty(reply)) return false; bFoundDone = ParseReceivedMessage(reply, "kill_done", args); if (bFoundDone) return true; } return (bFoundAck && bFoundDone); } } /// /// This class encapsulates the functionality of the synctool used by CafeX. /// static class synctool { static string exe_path = "\"" + Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\synctool.exe" + "\""; internal static int sync(string cfg, string src, string dst, string log) { #if DEBUG Log.WriteLine("synctool.sync started."); #endif FileUtil.AddQuotes(ref src); FileUtil.AddQuotes(ref dst); string output = string.Empty; int ret = ProcessExecutor.DoProcess_GetOutput(exe_path, "-cfgxml " + cfg + " " + src + " " + dst + " ", out output); FileStream fs = new FileStream(log, FileMode.Create); StreamWriter sw = new StreamWriter(fs); sw.Write(output); sw.Flush(); sw.Close(); return ret; } } /// /// This class encapsulates the functionality of the pcfsserversync tool used by CafeX. /// static class PCFSServerSync { static string exe_path = Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\PCFSServerSync.exe"; internal static int sync(string date, string elf, string mapping) { #if DEBUG Log.WriteLine("PCFSServerSync.sync started."); #endif return ProcessExecutor.DoProcess(exe_path, "-comment \"cafex run: ----- [" + date + "] Launching " + Path.GetFileName(elf) + " -----\" " + Environment.GetEnvironmentVariable("PCFS_HEADLESS_EMUL") + " -softlaunch -message " + mapping); } internal static int wait_sync(string date) { #if DEBUG Log.WriteLine("PCFSServerSync.wait_sync started."); #endif return ProcessExecutor.DoProcess(exe_path, "-wait 25000 " + Environment.GetEnvironmentVariable("PCFS_HEADLESS_EMUL") + " -comment cafex run: [" + date + "] ----- Hard-launch Startup Complete -----"); } } /// /// This class encapsulates the functionality of the ImageUploader tool used by CafeX. /// static class ImageUploader { static string exe_path = Environment.GetEnvironmentVariable("MION_BRIDGE_TOOLS") + "\\ImageUploader.exe"; internal static int upload(string ip, int bankno, string wumad_file) { #if DEBUG Log.WriteLine("ImageUploader.upload started."); #endif DataReceivedEventHandler callback = (sender, e) => { if (e != null && e.Data != null) { Console.WriteLine(e.Data); } }; return ProcessExecutor.StartProcess_RedirectOutput(exe_path, string.Format("-ip {0} -upload {1} -w {2}", ip, bankno, wumad_file), callback, true); } } /// /// This class encapsulates the functionality of the winmakebsf tool used by CafeX. /// static class makebsf { static string exe_path = "\"" + Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\winmakebsf.exe" + "\""; internal static int make(string quiet, string bsf_file, string flags) { #if DEBUG Log.WriteLine("makebsf.make started."); #endif FileUtil.AddQuotes(ref bsf_file); string output = string.Empty; int ret = ProcessExecutor.DoProcess_GetOutput(exe_path, quiet + " -i 0x20008000 -j 0x20008800 -o " + bsf_file + " -f " + flags, out output); if (!string.IsNullOrEmpty(output)) { Console.Write(output); } return ret; } } /// /// This class encapsulates the functionality of the winmakedlf tool used by CafeX. /// static class makedlf { static string exe_path = "\"" + Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\winmakedlf.exe" + "\""; internal static int make(string quiet, string file_list, string output_dlf_file, out string commandResult) { #if DEBUG Log.WriteLine("makedlf.make started."); #endif commandResult = string.Empty; FileUtil.AddQuotes(ref file_list); FileUtil.AddQuotes(ref output_dlf_file); return ProcessExecutor.DoProcess_GetOutput(exe_path, quiet + " -p " + file_list + " -l 0x0,0x80000,0x90000 -o " + output_dlf_file, out commandResult); } } /// /// This class encapsulates the functionality of the makewumaddlf tool used by CafeX. /// static class makewumaddlf { static string exe_path = "\"" + Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\mastering\\makewumaddlf.exe" + "\""; internal static int make(string wumadFile, string extractionFolder, string output_dlf_file) { #if DEBUG Log.WriteLine("make_wumad_dlf make started."); #endif FileUtil.AddQuotes(ref extractionFolder); FileUtil.AddQuotes(ref output_dlf_file); // In case the file is null, adjust the parameters accordingly if (!string.IsNullOrEmpty(wumadFile)) { FileUtil.AddQuotes(ref wumadFile); wumadFile = wumadFile + " "; } DataReceivedEventHandler callback = (sender, e) => { if (e != null && e.Data != null) { Console.WriteLine(e.Data); } }; return ProcessExecutor.StartProcess_RedirectOutput(exe_path, wumadFile + extractionFolder + " " + output_dlf_file, callback, true); } } /// /// This class encapsulates the functionality of the cafemakedlf tool used by CafeX. /// static class cafemakedlf { static string exe_path = "\"" + Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\mastering\\cafemakedlf.exe" + "\""; internal static int make(string default_ddf, string common_ddf_file, string individual_ddf_file, string options) { #if DEBUG Log.WriteLine("cafemakedlf.make started."); #endif FileUtil.AddQuotes(ref default_ddf); FileUtil.AddQuotes(ref common_ddf_file); string arguments = "-uf " + default_ddf + " " + common_ddf_file + " "; if (individual_ddf_file != null) { FileUtil.AddQuotes(ref individual_ddf_file); arguments += " " + individual_ddf_file; } if (options != null) { arguments += " " + options; } return ProcessExecutor.DoProcess(exe_path, arguments); } } /// /// This class encapsulates the functionality of the multi compiler used by CafeX. /// static class multi { static string exe_path = "\"" + Environment.GetEnvironmentVariable("GHS_ROOT") + "\\multi.exe" + "\""; internal static int start(string multi_connect, string cafe_multi_init, string multielf) { #if DEBUG Log.WriteLine("multi.start started."); #endif String ProfCmd = ""; String ProfComment = Path.GetFileName(multielf); // change wacks so it prints out as a string nicely... FileUtil.AddQuotes(ref multielf); if (Program.CAFE_PROFILE.value != null && Program.CAFE_PROFILE.value == "1") { CafeXEventtLog.Instance.WriteToEventLog(900, DateTime.Now, ProfComment); String ProfFunc = "eventCreate2 /id 901 /d " + ProfComment; // the ugliest line of code in the entire world ProfCmd = "-cmd \"python -b -s \\\"os.system('" + ProfFunc + "')\\\"\" "; } String ExeCmd = "-cmd prepare_target " + multi_connect + " " + cafe_multi_init + " " + ProfCmd + multielf; // Console.WriteLine("\n---------------\n" + exe_path + " " + ExeCmd + "\n-------------\n"); return ProcessExecutor.DoProcess_DontWait(exe_path, ExeCmd); } } internal enum SyncStage { None, Busy, Boot, TitleSoft, TitleFast, Menu, } /// /// This class emulates the functionality of the cattoucan tool. /// static class cattoucan { private static List> notifyList = new List>(); private static List>> callbackList = new List>>(); internal static SyncStage sync = SyncStage.None; private static Nintendo.SDSG.CatToucan toucan; private static EventWaitHandle evtHandle = null; private static Thread cattoucanThread = null; private static Nintendo.SDSG.CatToucan.ExitReason exit_reason = null; static void outputThread(object arg) { // Start relaying data exit_reason = toucan.RelaySerialCharacters(Program.quiet_mode ? TextWriter.Null : Console.Out, true); lock (cattoucanThread) { toucan = null; } // We don't expect for toucan to exit if we're trying to sync something if (sync != SyncStage.None) { Console.WriteLine("cafex {0}: WARNING: CatToucan exited during sync! Cafex Code={1}, App Code={2}, Sync={3}", Program.command, exit_reason.reason, exit_reason.AppExitCode, sync); } #if DEBUG Log.WriteLine("cattoucan exiting with reason = " + exit_reason.reason); Log.WriteLine("Application exited with code " + exit_reason.AppExitCode); #endif if (exit_reason.reason == Nintendo.SDSG.CatToucan.ExitReason.Reason.StoppedDueToDroppedConnection) { Console.WriteLine("cafex : connection to CAT-DEV on port {0} failed or was dropped.", arg); } } static void createCattoucan(bool exclusive_match) { string port = Program.SESSION_DEBUG_OUT_PORT.value; #if DEBUG Log.WriteLine("cattoucan.start started. port=" + port); #endif if (port.StartsWith("localhost:")) { port = port.Remove(0, 10); } #if DEBUG Log.WriteLine("cattoucan starting to read from port " + port); #endif toucan = new Nintendo.SDSG.CatToucan(Convert.ToInt32(port)); foreach (KeyValuePair kvp in notifyList) { toucan.AddNotification(kvp); } foreach (KeyValuePair> kvp in callbackList) { toucan.AddNotification(kvp); } toucan.ExclusiveMatch = exclusive_match; cattoucanThread = new Thread(new ParameterizedThreadStart(outputThread)); cattoucanThread.Start(port); } internal static int start(bool no_console, bool exclusive_match) { if (Program.quiet_mode) { stopCattoucan(); #if DEBUG Log.WriteLine("cattoucan DID NOT START because quiet is true"); #endif return 0; } if (cattoucanThread != null) { lock (cattoucanThread) { if (toucan != null) { toucan.ExclusiveMatch = exclusive_match; } } } else { createCattoucan(exclusive_match); } #if DEBUG Log.WriteLine("Joining cattoucan thread from start"); #endif cattoucanThread.Join(); cattoucanThread = null; #if DEBUG Log.WriteLine("Async cattoucan exited from start"); #endif return exit_reason.AppExitCode; } internal static int stopCattoucan() { if (cattoucanThread == null) { return -1; } #if DEBUG Log.WriteLine("Stopping relay"); #endif lock (cattoucanThread) { if (toucan != null) { toucan.StopRelay(); } } #if DEBUG Log.WriteLine("Joining cattoucan thread from stop"); #endif cattoucanThread.Join(); cattoucanThread = null; #if DEBUG Log.WriteLine("Async cattoucan stopped"); #endif if (exit_reason.reason != Nintendo.SDSG.CatToucan.ExitReason.Reason.StoppedDueToDroppedConnection) { return exit_reason.AppExitCode; } return 0; } internal static void AddNotification(string match, ManualResetEvent evt) { KeyValuePair kvp = new KeyValuePair(match, evt); if (toucan != null) { toucan.AddNotification(kvp); } notifyList.Add(kvp); } private static void closeEvent(ref EventWaitHandle evtHandle) { if (evtHandle != null) { evtHandle.Close(); evtHandle = null; } } internal static void AddNotification(string match, Func callback) { KeyValuePair> kvp = new KeyValuePair>(match, callback); if (toucan != null) { toucan.AddNotification(kvp); } int already = callbackList.IndexOf(kvp); if (already >= 0) { #if DEBUG Log.WriteLine("Overriding existing handler for '{0}'!", match); #endif callbackList.RemoveAt(already); } callbackList.Add(kvp); } internal static void ClearNotifications() { if (toucan != null) { toucan.ClearNotifications(); } notifyList.Clear(); callbackList.Clear(); } internal static void BeginBootSync() { sync = SyncStage.None; // Prepare cattoucan to wait for boot syncronization closeEvent(ref evtHandle); evtHandle = new EventWaitHandle(false, EventResetMode.ManualReset); if (cattoucanThread == null) { createCattoucan(false); } } internal static bool SendSyncRequest(int timeout) { if (evtHandle == null) { return false; } lock (cattoucanThread) { sync = SyncStage.None; } // Reset the handle and try sending the request evtHandle.Reset(); sync = SyncStage.Boot; return devkitmsg.help(timeout) == 0; } internal static void SignalBootEvent() { lock (cattoucanThread) { if (sync == SyncStage.Boot) { sync = SyncStage.None; evtHandle.Set(); } } } internal static bool SyncWithBoot(int timeout) { if (evtHandle == null) { return false; } // Wait for this message to be triggered Console.WriteLine("\nCafex {0}: Waiting for response...", Program.command); return evtHandle.WaitOne(timeout); } internal static void BeginTitleSoftSync() { sync = SyncStage.None; closeEvent(ref evtHandle); evtHandle = new EventWaitHandle(false, EventResetMode.AutoReset); sync = SyncStage.TitleSoft; if (cattoucanThread == null) { createCattoucan(false); } } internal static void BeginTitleFastSync() { stopCattoucan(); closeEvent(ref evtHandle); evtHandle = new EventWaitHandle(false, EventResetMode.AutoReset); sync = SyncStage.None; createCattoucan(true); } internal static void PrepareFastLaunch(int delay) { if (sync != SyncStage.Busy) { delay = 0; } lock (cattoucanThread) { sync = SyncStage.None; } if (delay != 0) { Thread.Sleep(delay); } sync = SyncStage.TitleFast; } internal static void SignalTitleEvent(SyncStage next) { lock (cattoucanThread) { if (sync != SyncStage.None) { #if DEBUG Log.WriteLine("Signaling title event, next=" + next.ToString()); #endif sync = next; evtHandle.Set(); } } } internal static bool SyncWithTitle(int timeout, bool stop) { if (evtHandle != null) { // Wait for the event to be called while (evtHandle.WaitOne(timeout)) { if (sync == SyncStage.None) { // Successfully called FinishSync(stop); return true; } if (sync == SyncStage.Busy) { return false; } } } return false; } internal static void BeginMenuSync() { if (cattoucanThread != null) { Monitor.Enter(cattoucanThread); } sync = SyncStage.None; if (cattoucanThread != null) { Monitor.Exit(cattoucanThread); } // Prepare cattoucan to wait for menu syncronization closeEvent(ref evtHandle); evtHandle = new EventWaitHandle(false, EventResetMode.ManualReset); sync = SyncStage.Menu; if (cattoucanThread == null) { createCattoucan(false); } } internal static void SignalMenuEvent() { lock (cattoucanThread) { sync = SyncStage.None; evtHandle.Set(); } } internal static void SyncWithMenu() { if (evtHandle != null) { // Wait for the event to be called evtHandle.WaitOne(); FinishSync(true); } } internal static void FinishSync(bool stop) { // Clear the sync flags if (cattoucanThread != null) { Monitor.Enter(cattoucanThread); sync = SyncStage.None; if (stop) { Monitor.Exit(cattoucanThread); // Stop async cattoucan stopCattoucan(); } } else { // Do not try and exit lock stop = true; } // Delete the event handles closeEvent(ref evtHandle); if (!stop) { Monitor.Exit(cattoucanThread); } } } /// /// This class encapsulates the functionality required to set the COM ports. /// static class cmd { static string exe_path = "cmd.exe"; internal static int mode(int comport) { #if DEBUG Log.WriteLine("cmd.mode started."); #endif return ProcessExecutor.DoProcess(exe_path, "mode.com com" + comport + ": BAUD=115200 PARITY=N DATA=8 STOP=1 to=off xon=off odsr=off octs=on dtr=off rts=on idsr=off"); } } /// /// This class encapsulates the functionality of the monitor tool used by CafeX. /// static class monitor { static string cygwin_monitor_exe_path = "\"" + Environment.GetEnvironmentVariable("CAFE_ROOT") + "\\system\\bin\\tool\\monitor.exe" + "\""; static readonly int MONITOR_FLUSH_TIME = 1; private static string GetExeName() { string monitor_or_temp_exe_path; if (FileUtil.RunningFromCygwin) { // take the monitor from cygwin monitor_or_temp_exe_path = cygwin_monitor_exe_path; } else { monitor_or_temp_exe_path = FileUtil.ExpandExecutable(CafeX.Properties.Resources.win_monitor, "win_monitor.exe"); } return monitor_or_temp_exe_path; } internal static int start(string str_opt, string test_str, string timeout, string rc_file, string log) { #if DEBUG Log.WriteLine("monitor.start started."); #endif string output = string.Empty; int ret = ProcessExecutor.DoProcess_GetOutput(GetExeName(), str_opt + " \"" + test_str + "\" -t " + timeout + " -p " + Environment.GetEnvironmentVariable("SESSION_DEBUG_OUT_PORT"), out output); FileStream fs = new FileStream(rc_file, FileMode.Create); StreamWriter sw = new StreamWriter(fs); sw.WriteLine(ret); sw.Flush(); sw.Close(); fs = new FileStream(log, FileMode.Create); sw = new StreamWriter(fs); sw.WriteLine(output); sw.Flush(); sw.Close(); return ret; } internal static int start_redirectionCallback(string str_opt, string test_str, string timeout, DataReceivedEventHandler callback) { #if DEBUG Log.WriteLine("start_redirectionCallback started."); #endif string output = string.Empty; int ret = ProcessExecutor.StartProcess_RedirectOutput(GetExeName(), str_opt + " \"" + test_str + "\" -t " + timeout + " -p " + Environment.GetEnvironmentVariable("SESSION_DEBUG_OUT_PORT"), callback, true); return ret; } internal static void flush() { #if DEBUG Log.WriteLine("monitor.flush started."); #endif int ret = ProcessExecutor.DoProcess(GetExeName(), "-t " + MONITOR_FLUSH_TIME + " -s " + MONITOR_FLUSH_TIME); #if DEBUG Log.WriteLine("monitor.flush returned = " + ret); #endif } } static class mionsig { static class HTML_CONTENT_TYPE { public const string APP_FORM_URL_ENCODED = "application/x-www-form-urlencoded"; } static class HTML_METHOD { public const string POST = "POST"; } internal const string MION_SIG_FMT_ADDR = "http://{0}/signal_get.cgi"; internal const string MION_ADMIN_USER = "mion"; internal const string MION_ADMIN_PASS = "/Multi_I/O_Network/"; internal const string HTML_TAG_END = ""; // Get message between "" tag static void getHtmlMsg(ref string response) { int end = response.IndexOf(HTML_TAG_END, StringComparison.OrdinalIgnoreCase); response = response.Substring(6, end - 6); } internal static int getVDD2() { int VDD2 = 0; try { // Setup web request to MION HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(string.Format(MION_SIG_FMT_ADDR, Program.BRIDGE_CURRENT_IP_ADDRESS.value)); byte[] data = Encoding.UTF8.GetBytes("sig=VDD2"); webReq.Method = HTML_METHOD.POST; webReq.ContentType = HTML_CONTENT_TYPE.APP_FORM_URL_ENCODED; webReq.PreAuthenticate = true; webReq.Credentials = new NetworkCredential(MION_ADMIN_USER, MION_ADMIN_PASS); webReq.ContentLength = data.Length; // Write the request to the stream using (Stream reqStream = webReq.GetRequestStream()) { reqStream.Write(data, 0, data.Length); reqStream.Flush(); } // Obtain the response data = null; HttpWebResponse webResp = (HttpWebResponse)webReq.GetResponse(); webReq = null; // Read response string response; using (Stream respStream = webResp.GetResponseStream()) { response = (new StreamReader(respStream)).ReadToEnd(); } webResp = null; // Parse VDD2 signal getHtmlMsg(ref response); int.TryParse(response, out VDD2); } // Any web or IO exception just report VDD2 as low catch (WebException e) { Console.WriteLine(e.Message); } catch (IOException e) { Console.WriteLine(e.Message); } return VDD2; } } }