Add Software
This commit is contained in:
parent
4d0b2610d9
commit
284cf95265
22 changed files with 657 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
*/*/bin/
|
||||||
|
*/*/obj/
|
||||||
|
*/bin/
|
||||||
|
*/obj/
|
9
LICENSE
Normal file
9
LICENSE
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Persephone (KawaiiZenbo) Bubblegum-Holiday
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
28
PC2SSTPlayer/INIFile.cs
Normal file
28
PC2SSTPlayer/INIFile.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace SSTServoPlayer
|
||||||
|
{
|
||||||
|
public class INIFile
|
||||||
|
{
|
||||||
|
public Dictionary<string, string> Data { get; set; }
|
||||||
|
|
||||||
|
public INIFile(Dictionary<string, string> data)
|
||||||
|
{
|
||||||
|
Data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static INIFile Load(string inPath)
|
||||||
|
{
|
||||||
|
Dictionary<string, string> outData = new Dictionary<string, string>();
|
||||||
|
string[] rawFile = File.ReadAllLines(inPath);
|
||||||
|
foreach (string line in rawFile)
|
||||||
|
{
|
||||||
|
if (line.StartsWith(";") || line.Trim() == "") continue;
|
||||||
|
outData.Add(line.Split("=")[0].Trim(), line.Split("=")[1].Trim());
|
||||||
|
}
|
||||||
|
return new INIFile(outData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
PC2SSTPlayer/PC2SSTPlayer.csproj
Normal file
14
PC2SSTPlayer/PC2SSTPlayer.csproj
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.IO.Ports" Version="10.0.0-preview.2.25163.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
67
PC2SSTPlayer/Program.cs
Normal file
67
PC2SSTPlayer/Program.cs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Ports;
|
||||||
|
using System.Text;
|
||||||
|
using System.Timers;
|
||||||
|
|
||||||
|
namespace SSTServoPlayer
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
static INIFile Config;
|
||||||
|
static string PathPrefix="/";
|
||||||
|
static byte[] Signals;
|
||||||
|
static SerialPort port = null;
|
||||||
|
static System.Timers.Timer FrameTimer;
|
||||||
|
static long index = 0;
|
||||||
|
static int frameSkip = 6;
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Config = INIFile.Load(args[0]);
|
||||||
|
PathPrefix = Path.GetFullPath(args[0]).Replace("manifest.ini", "");
|
||||||
|
Signals = File.ReadAllBytes(PathPrefix+Config.Data["data"]);
|
||||||
|
port = new SerialPort(args[1], 9600, Parity.None, 8, StopBits.One);
|
||||||
|
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
|
||||||
|
port.Open();
|
||||||
|
FrameTimer = new System.Timers.Timer((1000d/double.Parse(Config.Data["frames-per-second"]))*frameSkip);
|
||||||
|
FrameTimer.Elapsed += PlaySignal;
|
||||||
|
FrameTimer.AutoReset = true;
|
||||||
|
|
||||||
|
PlayAudio();
|
||||||
|
FrameTimer.Start();
|
||||||
|
Console.ReadLine();
|
||||||
|
port.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
||||||
|
{
|
||||||
|
Console.Write(port.ReadExisting());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PlayAudio()
|
||||||
|
{
|
||||||
|
Process.Start("mpv", PathPrefix+Config.Data["audio"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PlaySignal(Object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
if (index == Signals.Length)
|
||||||
|
{
|
||||||
|
FrameTimer.Stop();
|
||||||
|
Console.WriteLine("Complete!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte b = Signals[index];
|
||||||
|
|
||||||
|
byte byte1 = (byte)(64 | ((b & 8) | (b & 4) | (b & 2) | (b & 1)));
|
||||||
|
byte byte2 = (byte)(64 | (((b & 128) | (b & 64) | (b & 32) | (b & 16)) >> 4));
|
||||||
|
port.Write(((char)byte1).ToString());
|
||||||
|
port.Write(((char)byte2).ToString());
|
||||||
|
//port.Write(((char)b).ToString());
|
||||||
|
//Console.WriteLine(byte1.ToString("B8") + " " + byte2.ToString("B8"));
|
||||||
|
index+=frameSkip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
// PINKCONNECTION2 Client Program for Helen Henny/Chuck E./Guest Star Cyberamic Servo
|
||||||
|
|
||||||
|
#include <Servo.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
Servo servoChannel[8];
|
||||||
|
byte onDegrees[8] = { 90, 0, 0, 0, 0, 0, 0, 0 }; // these are incomplete, i need to tune them when i get the servos in
|
||||||
|
byte offDegrees[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
int byte1 = 0;
|
||||||
|
int byte2 = 0;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
servoChannel[0].attach(2);
|
||||||
|
servoChannel[1].attach(3);
|
||||||
|
servoChannel[2].attach(4);
|
||||||
|
servoChannel[3].attach(5);
|
||||||
|
servoChannel[4].attach(6);
|
||||||
|
servoChannel[5].attach(7);
|
||||||
|
servoChannel[6].attach(8);
|
||||||
|
servoChannel[7].attach(9);
|
||||||
|
pinMode(A0, OUTPUT);
|
||||||
|
pinMode(A1, OUTPUT);
|
||||||
|
pinMode(A2, OUTPUT);
|
||||||
|
pinMode(A3, OUTPUT);
|
||||||
|
pinMode(A4, OUTPUT);
|
||||||
|
pinMode(A5, OUTPUT);
|
||||||
|
pinMode(10, OUTPUT);
|
||||||
|
pinMode(11, OUTPUT);
|
||||||
|
for (int i = 0; i < 8; i++) servoChannel[i].write(offDegrees[i]);
|
||||||
|
Serial.begin(9600);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (Serial.available() > 1) {
|
||||||
|
byte1 = Serial.read();
|
||||||
|
byte2 = Serial.read();
|
||||||
|
if ((byte1 & 64) && (byte2 & 64))
|
||||||
|
if (byte1 & 1) {
|
||||||
|
servoChannel[0].write(onDegrees[0]);
|
||||||
|
digitalWrite(A0, 1);
|
||||||
|
} else {
|
||||||
|
servoChannel[0].write(offDegrees[0]);
|
||||||
|
digitalWrite(A0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte1 & 2) {
|
||||||
|
servoChannel[1].write(onDegrees[1]);
|
||||||
|
digitalWrite(A1, 1);
|
||||||
|
} else {
|
||||||
|
servoChannel[1].write(offDegrees[1]);
|
||||||
|
digitalWrite(A1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte1 & 4) {
|
||||||
|
servoChannel[2].write(onDegrees[2]);
|
||||||
|
digitalWrite(A2, 1);
|
||||||
|
} else {
|
||||||
|
servoChannel[2].write(offDegrees[2]);
|
||||||
|
digitalWrite(A2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte1 & 8) {
|
||||||
|
servoChannel[2].write(onDegrees[3]);
|
||||||
|
digitalWrite(A3, 1);
|
||||||
|
} else {
|
||||||
|
servoChannel[2].write(offDegrees[3]);
|
||||||
|
digitalWrite(A3, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte2 & 1) {
|
||||||
|
servoChannel[4].write(onDegrees[4]);
|
||||||
|
digitalWrite(A4, 1);
|
||||||
|
} else {
|
||||||
|
servoChannel[4].write(offDegrees[4]);
|
||||||
|
digitalWrite(A4, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte2 & 2) {
|
||||||
|
servoChannel[4].write(onDegrees[5]);
|
||||||
|
digitalWrite(A5, 1);
|
||||||
|
} else {
|
||||||
|
servoChannel[4].write(offDegrees[5]);
|
||||||
|
digitalWrite(A5, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte2 & 4) {
|
||||||
|
servoChannel[6].write(onDegrees[6]);
|
||||||
|
digitalWrite(10, 1);
|
||||||
|
} else {
|
||||||
|
servoChannel[6].write(offDegrees[6]);
|
||||||
|
digitalWrite(10, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte2 & 8) {
|
||||||
|
servoChannel[7].write(onDegrees[7]);
|
||||||
|
digitalWrite(11, 1);
|
||||||
|
} else {
|
||||||
|
servoChannel[7].write(offDegrees[7]);
|
||||||
|
digitalWrite(11, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<RootNamespace>PinkConnection2_TestApp.Gtk</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\PinkConnection2-TestApp\PinkConnection2-TestApp.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Eto.Platform.Gtk" Version="2.9.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using Eto.Forms;
|
||||||
|
|
||||||
|
namespace PinkConnection2_TestApp.Gtk
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
[STAThread]
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
new Application(Eto.Platforms.Gtk).Run(new MainForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
PinkConnection2-TestApp/PinkConnection2-TestApp.Mac/Icon.icns
Normal file
BIN
PinkConnection2-TestApp/PinkConnection2-TestApp.Mac/Icon.icns
Normal file
Binary file not shown.
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>PinkConnection2-TestApp</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>me.kawaiizenbo.PinkConnection2-TestApp</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>10.15</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string></string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>Icon.icns</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<RootNamespace>PinkConnection2_TestApp.Mac</RootNamespace>
|
||||||
|
|
||||||
|
<RuntimeIdentifiers>osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\PinkConnection2-TestApp\PinkConnection2-TestApp.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Eto.Platform.Mac64" Version="2.9.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using Eto.Forms;
|
||||||
|
|
||||||
|
namespace PinkConnection2_TestApp.Mac
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
[STAThread]
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
new Application(Eto.Platforms.Mac64).Run(new MainForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<RootNamespace>PinkConnection2_TestApp.Wpf</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\PinkConnection2-TestApp\PinkConnection2-TestApp.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Eto.Platform.Wpf" Version="2.9.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using Eto.Forms;
|
||||||
|
|
||||||
|
namespace PinkConnection2_TestApp.Wpf
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
[STAThread]
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
new Application(Eto.Platforms.Wpf).Run(new MainForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
105
PinkConnection2-TestApp/PinkConnection2-TestApp/MainForm.cs
Normal file
105
PinkConnection2-TestApp/PinkConnection2-TestApp/MainForm.cs
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
using System;
|
||||||
|
using System.IO.Ports;
|
||||||
|
|
||||||
|
using Eto.Forms;
|
||||||
|
using Eto.Drawing;
|
||||||
|
|
||||||
|
namespace PinkConnection2_TestApp
|
||||||
|
{
|
||||||
|
public class MainForm : Form
|
||||||
|
{
|
||||||
|
SerialPort port = null;
|
||||||
|
byte b = 0;
|
||||||
|
|
||||||
|
TextBox CommandTextBox = new TextBox { MaxLength = 2 };
|
||||||
|
DropDown SerialPortDropDown = new DropDown();
|
||||||
|
|
||||||
|
public MainForm()
|
||||||
|
{
|
||||||
|
Title = "PinkConnection2 Test App";
|
||||||
|
Size = new Size(480, 300);
|
||||||
|
Maximizable = false;
|
||||||
|
Resizable = false;
|
||||||
|
|
||||||
|
foreach (string s in SerialPort.GetPortNames())
|
||||||
|
{
|
||||||
|
SerialPortDropDown.Items.Add(s);
|
||||||
|
}
|
||||||
|
SerialPortDropDown.SelectedValueChanged += (sender, e) => selectSerialPort();
|
||||||
|
|
||||||
|
DynamicLayout layout = new DynamicLayout { DefaultSpacing = new Size(10, 10), DefaultPadding = new Padding(5, 5, 5, 5) };
|
||||||
|
|
||||||
|
layout.BeginVertical();
|
||||||
|
layout.BeginHorizontal();
|
||||||
|
layout.Add(new Label { Text = "Serial Port" });
|
||||||
|
layout.EndHorizontal();
|
||||||
|
|
||||||
|
layout.BeginHorizontal();
|
||||||
|
layout.Add(SerialPortDropDown, true);
|
||||||
|
layout.EndHorizontal();
|
||||||
|
layout.EndVertical();
|
||||||
|
|
||||||
|
layout.BeginVertical();
|
||||||
|
layout.BeginHorizontal();
|
||||||
|
layout.Add(new Label { Text = "Channels" });
|
||||||
|
layout.EndHorizontal();
|
||||||
|
|
||||||
|
layout.BeginHorizontal();
|
||||||
|
layout.Add(new Button { Text = "Channel 1", Command = new Command((sender, e) => { if ((b&1)==1) b-=1; else b+=1; sendFrame(); }) }, true);
|
||||||
|
layout.Add(new Button { Text = "Channel 2", Command = new Command((sender, e) => { if ((b&2)==2) b-=2; else b+=2; sendFrame(); }) }, true);
|
||||||
|
layout.Add(new Button { Text = "Channel 3", Command = new Command((sender, e) => { if ((b&4)==4) b-=4; else b+=4; sendFrame(); }) }, true);
|
||||||
|
layout.Add(new Button { Text = "Channel 4", Command = new Command((sender, e) => { if ((b&8)==8) b-=8; else b+=8; sendFrame(); }) }, true);
|
||||||
|
layout.EndHorizontal();
|
||||||
|
|
||||||
|
layout.BeginHorizontal();
|
||||||
|
layout.Add(new Button { Text = "Channel 5", Command = new Command((sender, e) => { if ((b&16)==16) b-=16; else b+=16; sendFrame(); }) }, true);
|
||||||
|
layout.Add(new Button { Text = "Channel 6", Command = new Command((sender, e) => { if ((b&32)==32) b-=32; else b+=32; sendFrame(); }) }, true);
|
||||||
|
layout.Add(new Button { Text = "Channel 7", Command = new Command((sender, e) => { if ((b&64)==64) b-=64; else b+=64; sendFrame(); }) }, true);
|
||||||
|
layout.Add(new Button { Text = "Channel 8", Command = new Command((sender, e) => { if ((b&128)==128) b-=128; else b+=128; sendFrame(); }) }, true);
|
||||||
|
layout.EndHorizontal();
|
||||||
|
layout.EndVertical();
|
||||||
|
|
||||||
|
layout.BeginVertical();
|
||||||
|
layout.BeginHorizontal();
|
||||||
|
layout.Add(new Label { Text = "Send Command" });
|
||||||
|
layout.EndHorizontal();
|
||||||
|
|
||||||
|
layout.BeginHorizontal();
|
||||||
|
layout.Add(CommandTextBox, true);
|
||||||
|
layout.Add(new Button { Text = "Send", Command = new Command((sender, e) => sendRawSafe()) });
|
||||||
|
layout.EndHorizontal();
|
||||||
|
layout.EndVertical();
|
||||||
|
|
||||||
|
layout.BeginVertical();
|
||||||
|
layout.Add(null, true);
|
||||||
|
layout.EndVertical();
|
||||||
|
|
||||||
|
Content = layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendFrame()
|
||||||
|
{
|
||||||
|
byte byte1 = (byte)(64 | ((b & 8) | (b & 4) | (b & 2) | (b & 1)));
|
||||||
|
byte byte2 = (byte)(64 | (((b & 128) | (b & 64) | (b & 32) | (b & 16)) >> 4));
|
||||||
|
port.Write(((char)byte1).ToString());
|
||||||
|
port.Write(((char)byte2).ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendRawSafe()
|
||||||
|
{
|
||||||
|
if (CommandTextBox.Text.Length != 2)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Command Length must not be less than 2");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
port.Write(CommandTextBox.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectSerialPort()
|
||||||
|
{
|
||||||
|
if (port != null) port.Close();
|
||||||
|
port = new SerialPort((string)SerialPortDropDown.SelectedKey, 9600, Parity.None, 8, StopBits.One);
|
||||||
|
port.Open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<RootNamespace>PinkConnection2_TestApp</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Eto.Forms" Version="2.9.0" />
|
||||||
|
<PackageReference Include="System.IO.Ports" Version="10.0.0-preview.2.25163.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
2
PinkConnection2-TestApp/build_linux.sh
Executable file
2
PinkConnection2-TestApp/build_linux.sh
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
cd PinkConnection2-TestApp.Gtk
|
||||||
|
dotnet build
|
2
PinkConnection2-TestApp/build_mac.sh
Executable file
2
PinkConnection2-TestApp/build_mac.sh
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
cd PinkConnection2-TestApp.Mac
|
||||||
|
dotnet build
|
3
PinkConnection2-TestApp/build_windows.bat
Normal file
3
PinkConnection2-TestApp/build_windows.bat
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
@ECHO OFF
|
||||||
|
cd PinkConnection2-TestApp.Wpf
|
||||||
|
dotnet build
|
149
rshw2sst/Program.cs
Normal file
149
rshw2sst/Program.cs
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace rshw2sst
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
static bool usingRSHW = false;
|
||||||
|
static int charaIndex = 0;
|
||||||
|
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("RSHW and CSHW Data Converter");
|
||||||
|
if (args[0] == "help")
|
||||||
|
{
|
||||||
|
Console.WriteLine("Usage: rshw2sst <file path> <character> <output directory>\n"
|
||||||
|
+ "This will output a SST Showtape for 1 Cyberamic Character\n"
|
||||||
|
+ "If an RSHW file is used, it will convert the bits according to Rosetta\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!File.Exists(args[0]))
|
||||||
|
{
|
||||||
|
Console.WriteLine("FATAL: Specified file does not exist.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (Path.GetExtension(args[0]).ToLower())
|
||||||
|
{
|
||||||
|
case ".rshw":
|
||||||
|
usingRSHW = true;
|
||||||
|
break;
|
||||||
|
case ".cshw":
|
||||||
|
usingRSHW = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Console.WriteLine("FATAL: Only RSHW and CSHW files are supported.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (args[1].ToLower())
|
||||||
|
{
|
||||||
|
case "chuck":
|
||||||
|
charaIndex = 0;
|
||||||
|
break;
|
||||||
|
case "helen":
|
||||||
|
charaIndex = 1;
|
||||||
|
break;
|
||||||
|
case "munch":
|
||||||
|
charaIndex = 2;
|
||||||
|
break;
|
||||||
|
case "jasper":
|
||||||
|
charaIndex = 3;
|
||||||
|
break;
|
||||||
|
case "pasqually":
|
||||||
|
charaIndex = 4;
|
||||||
|
break;
|
||||||
|
case "bella":
|
||||||
|
Console.WriteLine("you wish!!!");
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
Console.WriteLine("FATAL: Invalid character.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Directory.Exists(args[2])) Directory.CreateDirectory(args[2]);
|
||||||
|
RSHWFile file = RSHWLoader.Load(args[0]);
|
||||||
|
if (file.signalData == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("FATAL: This file contains no signal data.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (file.audioData != null) File.WriteAllBytes(args[2] + "/audio_out.wav", file.audioData);
|
||||||
|
if (file.videoData != null) File.WriteAllBytes(args[2] + "/video_out.mp4", file.videoData);
|
||||||
|
Console.WriteLine("Wrote out audio and video data.");
|
||||||
|
|
||||||
|
List<BitArray> rshwBits = new List<BitArray>();
|
||||||
|
int countlength = 0;
|
||||||
|
if (file.signalData[0] != 0)
|
||||||
|
{
|
||||||
|
countlength = 1;
|
||||||
|
BitArray bit = new BitArray(300);
|
||||||
|
rshwBits.Add(bit);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < file.signalData.Length; i++)
|
||||||
|
{
|
||||||
|
if (file.signalData[i] == 0)
|
||||||
|
{
|
||||||
|
countlength += 1;
|
||||||
|
BitArray bit = new BitArray(300);
|
||||||
|
rshwBits.Add(bit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rshwBits[countlength - 1].Set(file.signalData[i], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine("Loaded RSHW signal data.");
|
||||||
|
|
||||||
|
List<byte> writeOut = new List<byte>();
|
||||||
|
long bitsOut = 0;
|
||||||
|
foreach (BitArray bits in rshwBits)
|
||||||
|
{
|
||||||
|
bitsOut++;
|
||||||
|
if (bitsOut % 6 != 0) continue;
|
||||||
|
byte frameByte = 0;
|
||||||
|
Dictionary<int, byte>[] mapping = RosettaR12;
|
||||||
|
if (usingRSHW) mapping = Rosetta3St;
|
||||||
|
foreach (KeyValuePair<int, byte> movement in mapping[charaIndex])
|
||||||
|
{
|
||||||
|
if (bits.Get(movement.Key)) frameByte += movement.Value;
|
||||||
|
}
|
||||||
|
writeOut.Add(frameByte);
|
||||||
|
}
|
||||||
|
File.WriteAllBytes(args[2] + "/signals_out.sts", writeOut.ToArray());
|
||||||
|
Console.WriteLine("Wrote out signal data.");
|
||||||
|
|
||||||
|
File.WriteAllText(args[2] + "/manifest.ini", $"; Exported by RSHW2SST\nname={Path.GetFileNameWithoutExtension(args[0])} {args[1]}\nvideo=video_out.mp4\naudio=audio_out.wav\ndata=signals_out.sts\nframes-per-second=10\nbits-per-frame=8");
|
||||||
|
Console.WriteLine("Wrote out manifest.");
|
||||||
|
if (file.videoData == null) Console.WriteLine("Warning: Video data was blank, you will need to add the file manually.");
|
||||||
|
Console.WriteLine("Complete!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Dictionary<int, byte>[] Rosetta3St =
|
||||||
|
{
|
||||||
|
new Dictionary<int, byte>
|
||||||
|
{ {1, 1}, {8, 2}, {7, 4}, {6, 8}, {5, 16}, {4, 32}, {2, 64}, {19, 128} }, // chuck
|
||||||
|
new Dictionary<int, byte>
|
||||||
|
{ {185, 1}, {180, 2}, {179, 4}, {178, 8}, {184, 16}, {183, 32}, {181, 64}, {169, 128} }, // helen
|
||||||
|
new Dictionary<int, byte>
|
||||||
|
{ {45, 1}, {55, 2}, {54, 4}, {44, 8}, {43, 16}, {41, 32}, {60, 64}, {59, 128} }, // munch
|
||||||
|
new Dictionary<int, byte>
|
||||||
|
{ {166, 1}, {158, 2}, {157, 4}, {156, 8}, {153, 16}, {152, 32}, {151, 64}, {163, 128} }, // jasper
|
||||||
|
new Dictionary<int, byte>
|
||||||
|
{ {30, 1}, {21, 2}, {25, 4}, {29, 8}, {28, 16}, {26, 32}, {31, 64}, {35, 128} } // pasqually
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Dictionary<int, byte>[] RosettaR12 =
|
||||||
|
{
|
||||||
|
new Dictionary<int, byte>
|
||||||
|
{ {1, 1}, {4, 2}, {3, 4}, {2, 8}, {5, 16}, {8, 32}, {6, 64}, {7, 128} }, // chuck
|
||||||
|
new Dictionary<int, byte>
|
||||||
|
{ {65, 1}, {68, 2}, {67, 4}, {66, 8}, {69, 16}, {72, 32}, {70, 64}, {71, 128} }, // helen
|
||||||
|
new Dictionary<int, byte>
|
||||||
|
{ {49, 1}, {51, 2}, {50, 4}, {53, 8}, {56, 16}, {54, 32}, {55, 64}, {52, 128} }, // munch
|
||||||
|
new Dictionary<int, byte>
|
||||||
|
{ {17, 1}, {20, 2}, {19, 4}, {18, 8}, {21, 16}, {24, 32}, {22, 64}, {23, 128} }, // jasper
|
||||||
|
new Dictionary<int, byte>
|
||||||
|
{ {33, 1}, {35, 2}, {34, 4}, {37, 8}, {40, 16}, {38, 32}, {39, 64}, {36, 128} } // pasqually
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
31
rshw2sst/RSHWFile.cs
Normal file
31
rshw2sst/RSHWFile.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.Serialization.Formatters.Binary;
|
||||||
|
|
||||||
|
sealed class AntiUnityBinder : System.Runtime.Serialization.SerializationBinder
|
||||||
|
{
|
||||||
|
public override Type BindToType(string assemblyName, string typeName)
|
||||||
|
{
|
||||||
|
return Type.GetType(String.Format("RSHWFile, " + Assembly.GetExecutingAssembly().FullName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
public class RSHWFile
|
||||||
|
{
|
||||||
|
public byte[]? audioData { get; set; }
|
||||||
|
public int[]? signalData { get; set; }
|
||||||
|
public byte[]? videoData { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RSHWLoader
|
||||||
|
{
|
||||||
|
public static RSHWFile Load(string path)
|
||||||
|
{
|
||||||
|
BinaryFormatter formatter = new BinaryFormatter();
|
||||||
|
formatter.Binder = new AntiUnityBinder();
|
||||||
|
FileStream stream = File.OpenRead(path);
|
||||||
|
return (RSHWFile)formatter.Deserialize(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
11
rshw2sst/rshw2sst.csproj
Normal file
11
rshw2sst/rshw2sst.csproj
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
Loading…
Add table
Reference in a new issue