diff --git a/Arduino Firmware/Firmware-8Valve/Firmware-8Valve.ino b/Arduino Firmware/Firmware-8Valve/Firmware-8Valve.ino index e86b46c..9c4fd69 100644 --- a/Arduino Firmware/Firmware-8Valve/Firmware-8Valve.ino +++ b/Arduino Firmware/Firmware-8Valve/Firmware-8Valve.ino @@ -14,7 +14,7 @@ void setup() pinMode(8, OUTPUT); pinMode(9, OUTPUT); Serial.begin(9600); - Serial.write("PC2,8,Universal"); + Serial.write("PC2,8,Universal,END"); } void loop() diff --git a/Arduino Firmware/Servo/Firmware-Servo-ChuckEHelenGuestStar/Firmware-Servo-ChuckEHelenGuestStar.ino b/Arduino Firmware/Servo/Firmware-Servo-ChuckEHelenGuestStar/Firmware-Servo-ChuckEHelenGuestStar.ino index f56fd0f..17c095e 100644 --- a/Arduino Firmware/Servo/Firmware-Servo-ChuckEHelenGuestStar/Firmware-Servo-ChuckEHelenGuestStar.ino +++ b/Arduino Firmware/Servo/Firmware-Servo-ChuckEHelenGuestStar/Firmware-Servo-ChuckEHelenGuestStar.ino @@ -20,7 +20,7 @@ void setup() servoChannel[5].attach(7); for (int i = 0; i < 8; i++) servoChannel[mapping[i]].write(offDegrees[i]); Serial.begin(9600); - Serial.write("PC2,8,Chuck E./Helen/Guest Star"); + Serial.write("PC2,8,Chuck E./Helen/Guest Star,END"); } void loop() diff --git a/Arduino Firmware/Servo/Firmware-Servo-HelenMitzi/Firmware-Servo-HelenMitzi.ino b/Arduino Firmware/Servo/Firmware-Servo-HelenMitzi/Firmware-Servo-HelenMitzi.ino index a7269e6..6dfb626 100644 --- a/Arduino Firmware/Servo/Firmware-Servo-HelenMitzi/Firmware-Servo-HelenMitzi.ino +++ b/Arduino Firmware/Servo/Firmware-Servo-HelenMitzi/Firmware-Servo-HelenMitzi.ino @@ -2,10 +2,10 @@ #include -Servo servoChannel[11]; // mouth earL earR eyelidL eyelidR eyeL eyeR headR headL headUp armUpL armUpR elbowR elbowL armTwistL armTwistR bodyTwistR bodyTwistL bodyLean -byte onDegrees[19] = { 45, 0, 0, 0, 0, 0, 0, 45, 135, 135, 90, 90, 90, 90, 90, 90, 0, 0, 0 }; +Servo servoChannel[11]; // mouth earL earR eyelidL eyelidR eyeL eyeR headL headR headUp armUpL armUpR elbowR elbowL armTwistL armTwistR bodyTwistR bodyTwistL bodyLean +byte onDegrees[19] = { 45, 0, 0, 0, 0, 0, 0, 135, 45, 135, 90, 90, 90, 90, 90, 90, 0, 0, 0 }; byte offDegrees[19] = { 0, 0, 0, 0, 0, 0, 0, 90, 90, 90, 180, 0, 0, 180, 180, 0 , 0, 0, 0 }; -byte mapping[19] = { 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 6, 3, 4, 7, 8, 5, 0, 0, 0 }; +byte mapping[19] = { 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 6, 3, 4, 7, 8, 5, 9, 9, 10 }; int byte1 = 0; int byte2 = 0; @@ -29,7 +29,7 @@ void setup() servoChannel[8].attach(10); for (int i = 0; i < 19; i++) servoChannel[mapping[i]].write(offDegrees[i]); Serial.begin(9600); - Serial.write("PC2,32,Mitzi/Helen"); + Serial.write("PC2,32,Mitzi/Helen,END"); } void loop() { diff --git a/PC2Player/PC2Player/MainForm.cs b/PC2Player/PC2Player/MainForm.cs index f3bc1a3..1a03aaf 100644 --- a/PC2Player/PC2Player/MainForm.cs +++ b/PC2Player/PC2Player/MainForm.cs @@ -1,4 +1,11 @@ using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.IO.Ports; +using System.Timers; + using Eto.Forms; using Eto.Drawing; @@ -6,52 +13,298 @@ namespace PC2Player { public partial class MainForm : Form { + SerialPort Port = null; + string[] Signals; + System.Timers.Timer FrameTimer; + long Index = 0; + int FrameSkip = 6; + byte[] AudioData; + + string ShowtapeName = ""; + string ShowtapeStageType = ""; + string ShowtapeCharacter = ""; + string ShowtapeBits = ""; + string ShowtapeFormattedLength = ""; + + string ControllerCharacter = ""; + string ControllerBits = ""; + + string ControllerHeader = ""; + + bool ControllerConnected = false; + bool ShowtapeLoaded = false; + + bool Playing = false; + + DropDown SerialPortDropDown = new DropDown(); + + Label ShowtapeNameLabel = new Label { Text = "Show Name: Not Loaded" }; + Label ShowtapeStageTypeLabel = new Label { Text = "Stage Type: Not Loaded" }; + Label ShowtapeCharacterLabel = new Label { Text = "Character: Not Loaded" }; + Label ShowtapeBitsLabel = new Label { Text = "Bits: Not Loaded" }; + Label ShowtapeLengthLabel = new Label { Text = "Length: Not Loaded" }; + + Label ControllerCharacterLabel = new Label { Text = "Character: Disconnected" }; + Label ControllerBitsLabel = new Label { Text = "Bits: Disconnected" }; + + Button RefreshPortsButton = new Button { Text = "Refresh Ports", Width = 150 }; + Button LoadShowtapeButton = new Button { Text = "Load Showtape", Width = 150 }; + + Button PlayButton = new Button { Text = "Play" }; + Button StopButton = new Button { Text = "Stop" }; + public MainForm() { - Title = "My Eto Form"; - MinimumSize = new Size(200, 200); + Title = "PinkConnection2 Showtape Player"; + Size = new Size(500, 450); + Maximizable = false; + Resizable = false; - Content = new StackLayout + foreach (string s in SerialPort.GetPortNames()) { - Padding = 10, - Items = + SerialPortDropDown.Items.Add(s); + } + SerialPortDropDown.SelectedValueChanged += (sender, e) => Event_SelectSerialPort(); + + FrameTimer = new System.Timers.Timer((1000d/60d)*FrameSkip); + FrameTimer.Elapsed += Event_FrameTimerTick; + FrameTimer.AutoReset = true; + + PlayButton.Enabled = false; + StopButton.Enabled = false; + + PlayButton.Command = new Command( (sender, e) => Event_PlayButton() ); + StopButton.Command = new Command( (sender, e) => Event_StopButton() ); + RefreshPortsButton.Command = new Command( (sender, e) => Event_RefreshPortsButton() ); + LoadShowtapeButton.Command = new Command( (sender, e) => Event_LoadShowtapeButton() ); + + Content = BuildLayout(); + } + + DynamicLayout BuildLayout() + { + GroupBox showtapeInfoGroupBox = new GroupBox{ Text = "Showtape" }; + DynamicLayout showtapeInfoGroupLayout = new DynamicLayout { DefaultSpacing = new Size(5, 5), DefaultPadding = new Padding(5, 5, 5, 5) }; + showtapeInfoGroupLayout.AddRow(ShowtapeNameLabel); + showtapeInfoGroupLayout.AddRow(ShowtapeStageTypeLabel); + showtapeInfoGroupLayout.AddRow(ShowtapeCharacterLabel); + showtapeInfoGroupLayout.AddRow(ShowtapeBitsLabel); + showtapeInfoGroupLayout.AddRow(ShowtapeLengthLabel); + showtapeInfoGroupBox.Content = showtapeInfoGroupLayout; + + GroupBox controllerInfoGroupBox = new GroupBox{ Text = "Controller" }; + DynamicLayout controllerInfoGroupLayout = new DynamicLayout { DefaultSpacing = new Size(5, 5), DefaultPadding = new Padding(5, 5, 5, 5) }; + controllerInfoGroupLayout.AddRow(ControllerCharacterLabel); + controllerInfoGroupLayout.AddRow(ControllerBitsLabel); + controllerInfoGroupBox.Content = controllerInfoGroupLayout; + + DynamicLayout layout = new DynamicLayout { DefaultSpacing = new Size(10, 10), DefaultPadding = new Padding(5, 5, 5, 5) }; + + layout.BeginVertical(); + layout.BeginHorizontal(); + layout.Add(PlayButton, true); + layout.Add(StopButton, true); + layout.EndHorizontal(); + layout.EndVertical(); + + layout.BeginVertical(); + + layout.BeginHorizontal(); + layout.Add(new Label { Text = "Serial Port" }); + layout.EndHorizontal(); + + layout.BeginHorizontal(); + layout.Add(SerialPortDropDown, true); + layout.EndHorizontal(); + + layout.BeginHorizontal(); + layout.Add(showtapeInfoGroupBox, true); + layout.EndHorizontal(); + + layout.BeginHorizontal(); + layout.Add(controllerInfoGroupBox, true); + layout.EndHorizontal(); + + layout.EndVertical(); + + layout.BeginVertical(); + layout.BeginHorizontal(); + layout.Add(null, true); + layout.Add(RefreshPortsButton); + layout.Add(LoadShowtapeButton); + layout.EndHorizontal(); + layout.EndVertical(); + + layout.BeginVertical(); + layout.Add(null, true); + layout.EndVertical(); + + return layout; + } + + void CheckReady() + { + if (ControllerConnected && ShowtapeLoaded) + { + PlayButton.Enabled = true; + StopButton.Enabled = true; + } + else + { + PlayButton.Enabled = false; + StopButton.Enabled = false; + } + } + + void Event_SelectSerialPort() + { + if (Port != null) Port.Close(); + Port = new SerialPort((string)SerialPortDropDown.SelectedKey, 9600, Parity.None, 8, StopBits.One); + Port.DataReceived += new SerialDataReceivedEventHandler(Event_PortRecievedData); + ControllerHeader = ""; + ControllerCharacterLabel.Text = "Character: Disconnected"; + ControllerBitsLabel.Text = "Bits: Disconnected"; + ControllerConnected = false; + CheckReady(); + Port.Open(); + } + + void Event_PortRecievedData(object sender, SerialDataReceivedEventArgs e) + { + ControllerHeader += Port.ReadExisting(); + if (ControllerHeader.EndsWith(",END")) + { + ControllerBits = ControllerHeader.Split(',')[1]; + ControllerCharacter = ControllerHeader.Split(',')[2]; + + ControllerCharacterLabel.Text = $"Character: {ControllerCharacter}"; + ControllerBitsLabel.Text = $"Bits: {ControllerBits}"; + ControllerConnected = true; + CheckReady(); + } + } + + void Event_RefreshPortsButton() + { + foreach (string s in SerialPort.GetPortNames()) + { + SerialPortDropDown.Items.Add(s); + } + } + + void Event_LoadShowtapeButton() + { + OpenFileDialog fileDialog = new OpenFileDialog(); + fileDialog.Filters.Add(new FileFilter("UST Files (.ust)", new string[]{ ".ust" })); + fileDialog.Title = "Select Show File."; + fileDialog.ShowDialog(this); + + string tempUSTData = File.ReadAllText(fileDialog.FileName); + if (!tempUSTData.StartsWith("UST,1,")) + { + MessageBox.Show("This is not a UST Version 1 showtape."); + return; + } + + string[] headerData = tempUSTData.Split(';')[0].Split(','); + string[] stringyBits = tempUSTData.Split(';')[1].Split(','); + AudioData = Convert.FromBase64String(tempUSTData.Split(';')[2]); + + ShowtapeName = headerData[2]; + ShowtapeBits = headerData[3]; + ShowtapeStageType = headerData[4]; + ShowtapeCharacter = headerData[5]; + + if (headerData[3] == "256") + { + MessageBox.Show("Can't load a full stage showtape right now!"); + return; + } + + TimeSpan time = TimeSpan.FromSeconds(stringyBits.Length/60); + ShowtapeFormattedLength = time.ToString(@"hh\:mm\:ss"); + + ShowtapeNameLabel.Text = $"Show Name: {ShowtapeName}"; + ShowtapeStageTypeLabel.Text = $"Stage Type: {ShowtapeStageType}"; + ShowtapeCharacterLabel.Text = $"Character: {ShowtapeCharacter}"; + ShowtapeBitsLabel.Text = $"Bits: {ShowtapeBits}"; + ShowtapeLengthLabel.Text = $"Length: {ShowtapeFormattedLength}"; + + List tmpOut = new List(); + foreach (string frame in stringyBits) + { + int b = int.Parse(frame, NumberStyles.HexNumber); + char[] bytesOut = { (char)64 }; + if (ShowtapeBits == "8") { - "Hello World!", - // add more controls here + bytesOut = new char[]{ + (char)(64 | ((b & 8) | (b & 4) | (b & 2) | (b & 1))), + (char)(64 | (((b & 128) | (b & 64) | (b & 32) | (b & 16)) >> 4)) + }; } - }; + else if (ShowtapeBits == "32") + { + bytesOut = new char[]{ + (char)(64 | ((b & 8) | (b & 4) | (b & 2) | (b & 1))), + (char)(64 | (((b & 128) | (b & 64) | (b & 32) | (b & 16)) >> 4)), + (char)(64 | (((b & 2048) | (b & 1024) | (b & 512) | (b & 256)) >> 8)), + (char)(64 | (((b & 32768) | (b & 16384) | (b & 8192) | (b & 4096)) >> 12)), + (char)(64 | (((b & 524288) | (b & 262144) | (b & 131072) | (b & 65536)) >> 16)), + (char)(64 | (((b & 8388608) | (b & 4194304) | (b & 2097152) | (b & 1048576)) >> 20)), + (char)(64 | (((b & 134217728) | (b & 67108864) | (b & 33554432) | (b & 16777216)) >> 24)), + (char)(64 | (((b & 2147483648) | (b & 1073741824) | (b & 536870912) | (b & 268435456)) >> 28)) + }; + } + tmpOut.Add(new string(bytesOut)); + } + Signals = tmpOut.ToArray(); + ShowtapeLoaded = true; + CheckReady(); + } - // create a few commands that can be used for the menu and toolbar - var clickMe = new Command { MenuText = "Click Me!", ToolBarText = "Click Me!" }; - clickMe.Executed += (sender, e) => MessageBox.Show(this, "I was clicked!"); - - var quitCommand = new Command { MenuText = "Quit", Shortcut = Application.Instance.CommonModifier | Keys.Q }; - quitCommand.Executed += (sender, e) => Application.Instance.Quit(); - - var aboutCommand = new Command { MenuText = "About..." }; - aboutCommand.Executed += (sender, e) => new AboutDialog().ShowDialog(this); - - // create menu - Menu = new MenuBar + void Event_PlayButton() + { + if (Playing) return; + if (ShowtapeBits != ControllerBits) { - Items = - { - // File submenu - new SubMenuItem { Text = "&File", Items = { clickMe } }, - // new SubMenuItem { Text = "&Edit", Items = { /* commands/items */ } }, - // new SubMenuItem { Text = "&View", Items = { /* commands/items */ } }, - }, - ApplicationItems = - { - // application (OS X) or file menu (others) - new ButtonMenuItem { Text = "&Preferences..." }, - }, - QuitItem = quitCommand, - AboutItem = aboutCommand - }; + MessageBox.Show("This showtape does not have the correct amount of bits for your controller."); + return; + } + File.WriteAllBytes("tmp.wav", AudioData); + Process.Start("mpv", "tmp.wav"); + FrameTimer.Start(); - // create toolbar - ToolBar = new ToolBar { Items = { clickMe } }; + Playing = true; + + PlayButton.Enabled = false; + RefreshPortsButton.Enabled = false; + LoadShowtapeButton.Enabled = false; + SerialPortDropDown.Enabled = false; + } + + void Event_StopButton() + { + FrameTimer.Stop(); + File.Delete("tmp.wav"); + Playing = false; + + PlayButton.Enabled = true; + RefreshPortsButton.Enabled = true; + LoadShowtapeButton.Enabled = true; + SerialPortDropDown.Enabled = true; + Index = 0; + } + + void Event_FrameTimerTick(Object sender, ElapsedEventArgs e) + { + if (Index >= Signals.Length) + { + Event_StopButton(); + return; + } + + Port.Write(Signals[Index]); + Index += FrameSkip; } } } diff --git a/PC2Player/PC2Player/PC2Player.csproj b/PC2Player/PC2Player/PC2Player.csproj index f8e4f2a..2542e44 100644 --- a/PC2Player/PC2Player/PC2Player.csproj +++ b/PC2Player/PC2Player/PC2Player.csproj @@ -6,6 +6,7 @@ + - \ No newline at end of file +