summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2012-05-07 21:33:32 +0000
committerIan C <ianc@noddybox.co.uk>2012-05-07 21:33:32 +0000
commitca53eea76d082acb2724356eaba4b52cfe7b1584 (patch)
tree55f674ae9f7b4570df27399193787e8b8ef300c2
parent5f9b4b9c5dab70fd70be2872653e9fe6a7aced5a (diff)
Initial working tape routines
-rw-r--r--wpspec/wpspec/OpenRemoteTapePage.xaml52
-rw-r--r--wpspec/wpspec/OpenRemoteTapePage.xaml.cs10
-rw-r--r--wpspec/wpspec/Properties/WMAppManifest.xml12
-rw-r--r--wpspec/wpspec/Resources/Strings.Designer.cs54
-rw-r--r--wpspec/wpspec/Resources/Strings.resx18
-rw-r--r--wpspec/wpspec/Settings.cs6
-rw-r--r--wpspec/wpspec/Spectrum/Emulation.cs155
-rw-r--r--wpspec/wpspec/Spectrum/SpectrumKeySymbol.cs41
-rw-r--r--wpspec/wpspec/Spectrum/Tape.cs73
-rw-r--r--wpspec/wpspec/ViewModels/OpenRemoteTapeViewModel.cs128
-rw-r--r--wpspec/wpspec/wpspec.csproj3
11 files changed, 516 insertions, 36 deletions
diff --git a/wpspec/wpspec/OpenRemoteTapePage.xaml b/wpspec/wpspec/OpenRemoteTapePage.xaml
index 3016094..a223153 100644
--- a/wpspec/wpspec/OpenRemoteTapePage.xaml
+++ b/wpspec/wpspec/OpenRemoteTapePage.xaml
@@ -7,15 +7,17 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:res="clr-namespace:wpspec.Resources"
+ xmlns:conv="clr-namespace:wpspec.Converters"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
- mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
- shell:SystemTray.IsVisible="True">
+ mc:Ignorable="d" d:DesignHeight="800" d:DesignWidth="480"
+ shell:SystemTray.IsVisible="False">
<phone:PhoneApplicationPage.Resources>
<res:Strings x:Key="Strings" />
+ <conv:ConvertBooleanToVisibility x:Key="ConvertBooleanToVisibility" />
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
@@ -37,19 +39,39 @@
</StackPanel>
<!--ContentPanel - place additional content here-->
- <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"></Grid>
+ <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="auto"/>
+ <RowDefinition Height="*"/>
+ <RowDefinition Height="auto"/>
+ </Grid.RowDefinitions>
+ <TextBlock Grid.Row="0"
+ Text="{Binding SelectRemoteTapeText, Source={StaticResource Strings}}"/>
+ <TextBox Grid.Row="1"
+ Text="{Binding TapeName, Mode=TwoWay}"/>
+ <TextBlock Grid.Row="2"
+ Text="{Binding Message, Mode=OneWay}"
+ VerticalAlignment="Top"
+ HorizontalAlignment="Left"
+ TextWrapping="Wrap"/>
+ <Button Grid.Row="3"
+ IsEnabled="{Binding LoadOk, Mode=OneWay}"
+ Content="{Binding OpenRemoteTapeButtonText, Source={StaticResource Strings}}"
+ Click="OpenTapeClick"/>
+
+ <Canvas Grid.RowSpan="4"
+ Visibility="{Binding IsLoading, Converter={StaticResource ConvertBooleanToVisibility}}">
+ <Canvas.Background>
+ <SolidColorBrush Color="Black" Opacity="0.9"/>
+ </Canvas.Background>
+ </Canvas>
+ <TextBlock Grid.RowSpan="4"
+ Text="{Binding LoadingText, Source={StaticResource Strings}}"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Visibility="{Binding IsLoading, Converter={StaticResource ConvertBooleanToVisibility}}" />
+ </Grid>
</Grid>
- <!--Sample code showing usage of ApplicationBar-->
- <!--<phone:PhoneApplicationPage.ApplicationBar>
- <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
- <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
- <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
- <shell:ApplicationBar.MenuItems>
- <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
- <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
- </shell:ApplicationBar.MenuItems>
- </shell:ApplicationBar>
- </phone:PhoneApplicationPage.ApplicationBar>-->
-
</phone:PhoneApplicationPage>
diff --git a/wpspec/wpspec/OpenRemoteTapePage.xaml.cs b/wpspec/wpspec/OpenRemoteTapePage.xaml.cs
index 997411b..16a5a48 100644
--- a/wpspec/wpspec/OpenRemoteTapePage.xaml.cs
+++ b/wpspec/wpspec/OpenRemoteTapePage.xaml.cs
@@ -10,14 +10,24 @@ using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
+using wpspec.ViewModels;
namespace wpspec
{
public partial class OpenRemoteTapePage : PhoneApplicationPage
{
+ private OpenRemoteTapeViewModel model;
+
public OpenRemoteTapePage()
{
+ model = new OpenRemoteTapeViewModel();
+ DataContext = model;
InitializeComponent();
}
+
+ private void OpenTapeClick(object sender, RoutedEventArgs e)
+ {
+ model.LoadTape();
+ }
}
} \ No newline at end of file
diff --git a/wpspec/wpspec/Properties/WMAppManifest.xml b/wpspec/wpspec/Properties/WMAppManifest.xml
index 8e05044..52f32ba 100644
--- a/wpspec/wpspec/Properties/WMAppManifest.xml
+++ b/wpspec/wpspec/Properties/WMAppManifest.xml
@@ -4,19 +4,7 @@
<App xmlns="" ProductID="{915c2100-66c8-4c32-8980-0504548d291a}" Title="wpspec" RuntimeType="Silverlight" Version="1.0.0.0" Genre="apps.normal" Author="Ian Cowburn" Description="ZX Spectrum Emulator" Publisher="noddybox">
<IconPath IsRelative="true" IsResource="false">ApplicationIcon.png</IconPath>
<Capabilities>
- <Capability Name="ID_CAP_APPOINTMENTS" />
- <Capability Name="ID_CAP_CONTACTS" />
- <Capability Name="ID_CAP_GAMERSERVICES"/>
- <Capability Name="ID_CAP_IDENTITY_DEVICE"/>
- <Capability Name="ID_CAP_IDENTITY_USER"/>
- <Capability Name="ID_CAP_ISV_CAMERA" />
- <Capability Name="ID_CAP_LOCATION"/>
- <Capability Name="ID_CAP_MEDIALIB"/>
- <Capability Name="ID_CAP_MICROPHONE"/>
<Capability Name="ID_CAP_NETWORKING"/>
- <Capability Name="ID_CAP_PHONEDIALER"/>
- <Capability Name="ID_CAP_PUSH_NOTIFICATION"/>
- <Capability Name="ID_CAP_SENSORS"/>
<Capability Name="ID_CAP_WEBBROWSERCOMPONENT"/>
</Capabilities>
<Tasks>
diff --git a/wpspec/wpspec/Resources/Strings.Designer.cs b/wpspec/wpspec/Resources/Strings.Designer.cs
index 4a365f0..74d7d90 100644
--- a/wpspec/wpspec/Resources/Strings.Designer.cs
+++ b/wpspec/wpspec/Resources/Strings.Designer.cs
@@ -182,6 +182,15 @@ namespace wpspec.Resources {
}
/// <summary>
+ /// Looks up a localized string similar to Loading....
+ /// </summary>
+ public static string LoadingText {
+ get {
+ return ResourceManager.GetString("LoadingText", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Main Menu.
/// </summary>
public static string MainPageTitle {
@@ -236,6 +245,42 @@ namespace wpspec.Resources {
}
/// <summary>
+ /// Looks up a localized string similar to Failed to fetch tape; got error - &quot;{0}&quot;.
+ /// </summary>
+ public static string RemoteTapeFetchFailed {
+ get {
+ return ResourceManager.GetString("RemoteTapeFetchFailed", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Loaded tape OK. Remember to LOAD &quot;&quot; on the Spectrum..
+ /// </summary>
+ public static string RemoteTapeLoadedOk {
+ get {
+ return ResourceManager.GetString("RemoteTapeLoadedOk", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Failed to create a Web request for {0}.
+ /// </summary>
+ public static string RemoteTapeRequestFailure {
+ get {
+ return ResourceManager.GetString("RemoteTapeRequestFailure", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Failed to create a tape file from the file at URL {0}.
+ /// </summary>
+ public static string RemoteTapeWrong {
+ get {
+ return ResourceManager.GetString("RemoteTapeWrong", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Copyright of the included Spectrum 48K ROM is held by Amstrad PLC, and the ROM image is included with their kind permission..
/// </summary>
public static string ROMCopyrightText {
@@ -308,6 +353,15 @@ namespace wpspec.Resources {
}
/// <summary>
+ /// Looks up a localized string similar to Ignore MIME type of tape files.
+ /// </summary>
+ public static string SettingsIgnoreMimeText {
+ get {
+ return ResourceManager.GetString("SettingsIgnoreMimeText", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Settings.
/// </summary>
public static string SettingsPageTitle {
diff --git a/wpspec/wpspec/Resources/Strings.resx b/wpspec/wpspec/Resources/Strings.resx
index 46679e3..d85664c 100644
--- a/wpspec/wpspec/Resources/Strings.resx
+++ b/wpspec/wpspec/Resources/Strings.resx
@@ -160,6 +160,9 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
<data name="LicenseHyperlinkUri" xml:space="preserve">
<value>http://www.gnu.org/licenses/gpl.html</value>
</data>
+ <data name="LoadingText" xml:space="preserve">
+ <value>Loading...</value>
+ </data>
<data name="MainPageTitle" xml:space="preserve">
<value>Main Menu</value>
</data>
@@ -178,6 +181,18 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
<data name="OpenRemoteTapePageTitle" xml:space="preserve">
<value>Open Tape</value>
</data>
+ <data name="RemoteTapeFetchFailed" xml:space="preserve">
+ <value>Failed to fetch tape; got error - "{0}"</value>
+ </data>
+ <data name="RemoteTapeLoadedOk" xml:space="preserve">
+ <value>Loaded tape OK. Remember to LOAD "" on the Spectrum.</value>
+ </data>
+ <data name="RemoteTapeRequestFailure" xml:space="preserve">
+ <value>Failed to create a Web request for {0}</value>
+ </data>
+ <data name="RemoteTapeWrong" xml:space="preserve">
+ <value>Failed to create a tape file from the file at URL {0}</value>
+ </data>
<data name="ROMCopyrightText" xml:space="preserve">
<value>Copyright of the included Spectrum 48K ROM is held by Amstrad PLC, and the ROM image is included with their kind permission.</value>
</data>
@@ -202,6 +217,9 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
<data name="SettingsButtonText" xml:space="preserve">
<value>Settings</value>
</data>
+ <data name="SettingsIgnoreMimeText" xml:space="preserve">
+ <value>Ignore MIME type of tape files</value>
+ </data>
<data name="SettingsPageTitle" xml:space="preserve">
<value>Settings</value>
</data>
diff --git a/wpspec/wpspec/Settings.cs b/wpspec/wpspec/Settings.cs
index dcfeb23..1ddecbf 100644
--- a/wpspec/wpspec/Settings.cs
+++ b/wpspec/wpspec/Settings.cs
@@ -54,7 +54,11 @@ namespace wpspec
#region Private code
private static bool sound = Load("sound", true);
- private static string tapeUrl = Load("tapeurl", "http://enter-a-url.here/");
+#if DEBUG
+ private static string tapeUrl = Load("tapeurl", "http://noddybox.co.uk/spec");
+#else
+ private static string tapeUrl = Load("tapeurl", "http://enter-a-url.here/possible-path");
+#endif
private static T Load<T>(string name, T defaultValue)
{
diff --git a/wpspec/wpspec/Spectrum/Emulation.cs b/wpspec/wpspec/Spectrum/Emulation.cs
index 113a500..8cf6970 100644
--- a/wpspec/wpspec/Spectrum/Emulation.cs
+++ b/wpspec/wpspec/Spectrum/Emulation.cs
@@ -51,11 +51,27 @@ namespace wpspec.Spectrum
}
}
+ private const int ROM_SAVE=0x4c6;
+ private const int ROM_LOAD=0x562;
+ private const byte LOAD_PATCH=0xf0;
+ private const byte SAVE_PATCH=0xf1;
+
+ private readonly byte[] saveRoutine = {
+ 0xed, SAVE_PATCH, // ED SAVE_PATCH
+ 0xc9, // RET
+ 0xff // End of patch
+ };
+
+ private readonly byte[] loadRoutine = {
+ 0x08, // EX AF,AF'
+ 0xed, LOAD_PATCH, // ED LOAD_PATCH
+ 0xc9, // RET
+ 0xff // End of patch
+ };
+
private readonly byte[] mem = new byte[0x10000];
private readonly Clock clock = new Clock(0, 224, 312, 0);
- private byte[] tape;
-
private readonly byte[] matrix = new byte[9];
private readonly Dictionary<SpectrumKeySymbol, KeyMatrix> matrixLookup;
@@ -102,6 +118,22 @@ namespace wpspec.Spectrum
#region Private Members
+ private void RomPatch()
+ {
+ int f;
+
+ for(f=0; saveRoutine[f] != 0xff; f++)
+ {
+ mem[ROM_SAVE + f] = saveRoutine[f];
+ }
+
+ for(f=0; loadRoutine[f] != 0xff; f++)
+ {
+ mem[ROM_LOAD + f] = loadRoutine[f];
+ }
+ }
+
+
private void LineHandler(object sender, ClockEventArgs e)
{
ushort[] scr = Screen;
@@ -183,6 +215,116 @@ namespace wpspec.Spectrum
Z80.MaskableInterrupt(0xff);
}
+ private bool TapeLoad(Byte id, ref Register16 addr, ref Register16 len)
+ {
+ if (Tape == null)
+ {
+ return false;
+ }
+
+ bool result = false;
+ int block_len;
+ byte type;
+ byte csum;
+
+ block_len=Tape.ReadWord();
+ type = Tape.Read();
+ csum = id;
+
+ // Found the requested block?
+ //
+ if (id == type)
+ {
+ byte b = 0;
+ byte tape_csum;
+
+ // Knock off data block type
+ //
+ block_len--;
+
+ while(block_len > 0 && len.reg > 0)
+ {
+ b = Tape.Read();
+ csum ^= b;
+
+ if (addr.reg >= 0x4000)
+ {
+ mem[addr.reg] = b;
+ }
+
+ addr.reg++;
+ len.reg--;
+ block_len--;
+ }
+
+ // Get the checksum
+ //
+ if (block_len > 0)
+ {
+ tape_csum = Tape.Read();
+ block_len--;
+ }
+ else
+ {
+ tape_csum = b;
+ }
+
+ // In case we've been asked to load fewer bytes than are in the block
+ //
+ while (block_len-- > 0)
+ {
+ Tape.Read();
+ }
+
+ // Return the check sum test
+ //
+ result = (csum == tape_csum);
+ }
+ else
+ {
+ // It's the wrong block type, so skip it
+ //
+ while(block_len-- > 0)
+ {
+ Tape.Read();
+ }
+ }
+
+ return result;
+ }
+
+ private void EDHandler(object sender, Z80CpuEventArgs e)
+ {
+ switch (e.Opcode)
+ {
+ case LOAD_PATCH:
+ Register16 ix = Z80.IX_Register;
+ Register16 de = Z80.DE_Register;
+
+ if (TapeLoad(Z80.Acummulator, ref ix, ref de))
+ {
+ Z80.BC_Register = new Register16(0xb001);
+ Z80.StatusFlags |= Z80Flags.Carry;
+ }
+ else
+ {
+ Z80.BC_Register = new Register16(0xff01);
+ Z80.StatusFlags &= ~Z80Flags.Carry;
+ }
+
+ Z80.IX_Register = ix;
+ Z80.DE_Register = de;
+ break;
+
+ case SAVE_PATCH:
+ // No save support yet
+ break;
+
+ default:
+ break;
+ }
+ }
+
#endregion
#region IMemory Members
@@ -308,11 +450,7 @@ namespace wpspec.Spectrum
/// <summary>
/// Get/set the tape file to load.
/// </summary>
- public byte[] Tape
- {
- get {return tape;}
- set {tape = value;}
- }
+ public Tape Tape {get; set;}
/// <summary>
/// The Z80 CPU being used.
@@ -428,8 +566,8 @@ namespace wpspec.Spectrum
}
file.Stream.Read(mem, 0, 0x4000);
-
file.Stream.Close();
+ RomPatch();
// Set up screen and accelerators
//
@@ -517,6 +655,7 @@ namespace wpspec.Spectrum
// Initialise the CPU
//
+ Z80.EDNopEvent += EDHandler;
Z80.Initialise(this, this, clock);
Disassembler.Initialise(this);
diff --git a/wpspec/wpspec/Spectrum/SpectrumKeySymbol.cs b/wpspec/wpspec/Spectrum/SpectrumKeySymbol.cs
new file mode 100644
index 0000000..8869d99
--- /dev/null
+++ b/wpspec/wpspec/Spectrum/SpectrumKeySymbol.cs
@@ -0,0 +1,41 @@
+// This file is part of the wpspec Spectrum emulator.
+//
+// wpspec is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// wpspec is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Noddybox.Emulation. If not, see <http://www.gnu.org/licenses/>.
+//
+// Copyright (c) 2012 Ian Cowburn
+//
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+
+namespace wpspec.Spectrum
+{
+ /// <summary>
+ /// Enumerated type for all the symbols on the Spectrum keyboard.
+ /// </summary>
+ public enum SpectrumKeySymbol
+ {
+ Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9, Key0,
+ KeyQ, KeyW, KeyE, KeyR, KeyT, KeyY, KeyU, KeyI, KeyO, KeyP,
+ KeyA, KeyS, KeyD, KeyF, KeyG, KeyH, KeyJ, KeyK, KeyL, KeyEnter,
+ KeyCapsShift, KeyZ, KeyX, KeyC, KeyV, KeyB, KeyN, KeyM, KeySymbolShift, KeySpace
+ }
+}
diff --git a/wpspec/wpspec/Spectrum/Tape.cs b/wpspec/wpspec/Spectrum/Tape.cs
new file mode 100644
index 0000000..b8ce7be
--- /dev/null
+++ b/wpspec/wpspec/Spectrum/Tape.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+
+namespace wpspec.Spectrum
+{
+ /// <summary>
+ /// Provides a simple tape.
+ /// </summary>
+ public class Tape
+ {
+ private byte[] tape;
+ private int index;
+
+ /// <summary>
+ /// Read the next byte from the tape.
+ /// </summary>
+ /// <returns>The next byte.</returns>
+ public byte Read()
+ {
+ byte r = tape[index++];
+
+ if (index >= tape.Length)
+ {
+ index = 0;
+ }
+
+ return r;
+ }
+
+ /// <summary>
+ /// Read the next word from the tape in LSB format.
+ /// </summary>
+ /// <returns>The next word.</returns>
+ public int ReadWord()
+ {
+ int c1;
+ int c2;
+
+ c1=Read();
+ c2=Read();
+
+ return c1+(c2<<8);
+ }
+
+ /// <summary>
+ /// Constructs a tape.
+ /// </summary>
+ /// <param name="tape">The memory block holding the tape.</param>
+ public Tape(byte[] tape)
+ {
+ if (tape == null)
+ {
+ throw new ArgumentNullException("Tape cannot be null");
+ }
+
+ if (tape.Length < 1 || tape.Rank > 1)
+ {
+ throw new ArgumentOutOfRangeException("Tape cannot be zero-length or have more than one dimension");
+ }
+
+ this.tape = tape;
+ index = 0;
+ }
+ }
+}
diff --git a/wpspec/wpspec/ViewModels/OpenRemoteTapeViewModel.cs b/wpspec/wpspec/ViewModels/OpenRemoteTapeViewModel.cs
new file mode 100644
index 0000000..0066f00
--- /dev/null
+++ b/wpspec/wpspec/ViewModels/OpenRemoteTapeViewModel.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Collections.Generic;
+using System.Text;
+using wpspec.Resources;
+using wpspec.Spectrum;
+
+namespace wpspec.ViewModels
+{
+ public class OpenRemoteTapeViewModel : BaseViewModel
+ {
+ #region Private Data
+
+ private string tapeName;
+ private bool isLoading;
+ private string message;
+ private WebClient http;
+ private uint currentReq;
+
+ #endregion
+
+ #region Properties
+
+ public string TapeName
+ {
+ get {return tapeName;}
+ set {SetValue(ref tapeName, value, "TapeName");}
+ }
+
+ public string Message
+ {
+ get {return message;}
+ set {SetValue(ref message, value, "Message");}
+ }
+
+ public bool IsLoading
+ {
+ get {return isLoading;}
+ set {SetValue(ref isLoading, value, "IsLoading");}
+ }
+
+ #endregion
+
+ #region Private members
+
+ private Uri FormatUrl()
+ {
+ if (Settings.TapeUrl.EndsWith("/"))
+ {
+ return new Uri(String.Format("{0}{1}", Settings.TapeUrl, TapeName));
+ }
+ else
+ {
+ return new Uri(String.Format("{0}/{1}", Settings.TapeUrl, TapeName));
+ }
+ }
+
+ private void OnOpenComplete(object sender, OpenReadCompletedEventArgs e)
+ {
+ if (currentReq.Equals(e.UserState) && !e.Cancelled)
+ {
+ if (e.Error != null)
+ {
+ Message = String.Format(Strings.RemoteTapeFetchFailed, e.Error.Message);
+ }
+ else
+ {
+ try
+ {
+ byte[] b = new byte[e.Result.Length];
+
+ e.Result.Read(b, 0, b.Length);
+ Shared.Spectrum.Tape = new Tape(b);
+
+ Message = Strings.RemoteTapeLoadedOk;
+ }
+ catch (Exception)
+ {
+ Message = String.Format(Strings.RemoteTapeWrong, FormatUrl());
+ }
+ }
+
+ IsLoading = false;
+ }
+ }
+
+ #endregion
+
+ #region Public Members
+
+ public void LoadTape()
+ {
+ if (http.IsBusy)
+ {
+ http.CancelAsync();
+ }
+
+ http.OpenReadAsync(FormatUrl(), ++currentReq);
+
+ IsLoading = true;
+ }
+
+ #endregion
+
+ #region Constructors
+
+ public OpenRemoteTapeViewModel()
+ {
+ http = new WebClient();
+ http.AllowReadStreamBuffering = true;
+ http.OpenReadCompleted += OnOpenComplete;
+
+ currentReq = 0;
+
+ IsLoading = false;
+ }
+
+ #endregion
+ }
+}
diff --git a/wpspec/wpspec/wpspec.csproj b/wpspec/wpspec/wpspec.csproj
index 09ae6bf..8a4fd29 100644
--- a/wpspec/wpspec/wpspec.csproj
+++ b/wpspec/wpspec/wpspec.csproj
@@ -72,6 +72,7 @@
<Compile Include="AppServiceProvider.cs">
<DependentUpon>GamePage.xaml</DependentUpon>
</Compile>
+ <Compile Include="Converters\ConvertBooleanToVisibility.cs" />
<Compile Include="Converters\ConvertFlagsToString.cs" />
<Compile Include="Converters\ConvertIntToHex2.cs" />
<Compile Include="Converters\ConvertIntToHex4.cs" />
@@ -106,9 +107,11 @@
<Compile Include="Shared.cs" />
<Compile Include="Spectrum\Emulation.cs" />
<Compile Include="Spectrum\SpectrumKeySymbol.cs" />
+ <Compile Include="Spectrum\Tape.cs" />
<Compile Include="ViewModels\BaseViewModel.cs" />
<Compile Include="ViewModels\DisassemblerLine.cs" />
<Compile Include="ViewModels\DisassemblerViewModel.cs" />
+ <Compile Include="ViewModels\OpenRemoteTapeViewModel.cs" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">