using Contralto.Logging; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Contralto { /// /// The configuration of an Alto II to emulate /// public enum SystemType { /// /// System with the standard 1K ROM, 1K RAM /// OneKRom, /// /// System with 2K ROM, 1K RAM /// TwoKRom, /// /// System with 3K RAM /// ThreeKRam, } public enum PacketInterfaceType { /// /// Encapsulate frames inside raw ethernet frames on the host interface. /// Requires PCAP. /// EthernetEncapsulation, /// /// Encapsulate frames inside UDP datagrams on the host interface. /// UDPEncapsulation, /// /// No encapsulation; sent packets are dropped on the floor and no packets are received. /// None, } public enum AlternateBootType { None, Disk, Ethernet, } /// /// Encapsulates user-configurable settings. To be enhanced. /// public class Configuration { static Configuration() { // Initialize things to defaults. HostAddress = 0x22; AlternateBootType = AlternateBootType.Disk; BootAddress = 0; BootFile = 0; SystemType = SystemType.TwoKRom; InterlaceDisplay = false; ThrottleSpeed = true; ReadConfiguration(); } /// /// The type of Alto II to emulate /// public static SystemType SystemType; /// /// The currently loaded image for Drive 0 /// public static string Drive0Image; /// /// The currently loaded image for Drive 1 /// public static string Drive1Image; /// /// The Ethernet host address for this Alto /// public static byte HostAddress; /// /// The name of the Ethernet adaptor on the emulator host to use for Ethernet emulation /// public static string HostPacketInterfaceName; /// /// Whether any packet interfaces are available on the host /// public static bool HostRawEthernetInterfacesAvailable; /// /// The type of interface to use to host networking. /// public static PacketInterfaceType HostPacketInterfaceType; /// /// The type of Alternate Boot to apply /// public static AlternateBootType AlternateBootType; /// /// The address to boot at reset for a disk alternate boot /// public static ushort BootAddress; /// /// The file to boot at reset for an ethernet alternate boot /// public static ushort BootFile; /// /// Whether to render the display "interlaced" or not. /// public static bool InterlaceDisplay; /// /// Whether to cap execution speed at native execution speed or not. /// public static bool ThrottleSpeed; /// /// Reads the current configuration file from disk. /// /// TODO: use reflection to do this. /// public static void ReadConfiguration() { try { using (StreamReader configStream = new StreamReader("contralto.cfg")) { // // Config file consists of text lines containing name / value pairs: // // Whitespace is ignored // int lineNumber = 0; while (!configStream.EndOfStream) { lineNumber++; string line = configStream.ReadLine().Trim(); if (string.IsNullOrEmpty(line)) { continue; } // Find whitespace separating tokens int ws = line.IndexOfAny(new char[] { ' ', '\t' }); if (ws < 1) { Log.Write(LogType.Warning, LogComponent.Configuration, "Syntax error on line {0}. Ignoring.", lineNumber); continue; } string parameter = line.Substring(0, ws); string value = line.Substring(ws + 1, line.Length - ws - 1); try { switch (parameter.ToLowerInvariant()) { case "drive0image": Drive0Image = value; break; case "drive1image": Drive1Image = value; break; case "systemtype": SystemType = (SystemType)Enum.Parse(typeof(SystemType), value, true); break; case "hostaddress": HostAddress = Convert.ToByte(value, 8); break; case "hostpacketinterfacename": HostPacketInterfaceName = value; break; case "hostpacketinterfacetype": HostPacketInterfaceType = (PacketInterfaceType)Enum.Parse(typeof(PacketInterfaceType), value, true); break; case "alternateboottype": AlternateBootType = (AlternateBootType)Enum.Parse(typeof(AlternateBootType), value, true); break; case "bootaddress": BootAddress = Convert.ToUInt16(value, 8); break; case "bootfile": BootFile = Convert.ToUInt16(value, 8); break; case "interlacedisplay": InterlaceDisplay = bool.Parse(value); break; case "throttlespeed": ThrottleSpeed = bool.Parse(value); break; default: Log.Write(LogType.Warning, LogComponent.Configuration, "Invalid parameter on line {0}. Ignoring.", lineNumber); break; } } catch { Log.Write(LogType.Warning, LogComponent.Configuration, "Invalid value on line {0}. Ignoring.", lineNumber); continue; } } } } catch (Exception) { Log.Write(LogType.Warning, LogComponent.Configuration, "Configuration file 'contralto.cfg' could not be read; assuming default settings."); WriteConfiguration(); } } /// /// Commits the current configuration to disk. /// public static void WriteConfiguration() { try { using (StreamWriter configStream = new StreamWriter("contralto.cfg")) { if (!string.IsNullOrEmpty(Drive0Image)) { configStream.WriteLine("Drive0Image {0}", Drive0Image); } if (!string.IsNullOrEmpty(Drive1Image)) { configStream.WriteLine("Drive1Image {0}", Drive1Image); } configStream.WriteLine("SystemType {0}", SystemType); configStream.WriteLine("HostAddress {0}", Conversion.ToOctal(HostAddress)); if (!string.IsNullOrEmpty(HostPacketInterfaceName)) { configStream.WriteLine("HostPacketInterfaceName {0}", HostPacketInterfaceName); } configStream.WriteLine("HostPacketInterfaceType {0}", HostPacketInterfaceType); configStream.WriteLine("AlternateBootType {0}", AlternateBootType); configStream.WriteLine("BootAddress {0}", Conversion.ToOctal(BootAddress)); configStream.WriteLine("BootFile {0}", Conversion.ToOctal(BootFile)); configStream.WriteLine("InterlaceDisplay {0}", InterlaceDisplay); configStream.WriteLine("ThrottleSpeed {0}", ThrottleSpeed); } } catch (Exception) { Log.Write(LogType.Warning, LogComponent.Configuration, "Configuration file 'contralto.cfg' could not be opened for writing."); } } } }