Added support for USB-botbase (#299)

Only for player item injection at this time; no sync / toggle between modes
This commit is contained in:
berichan
2020-06-06 20:58:13 +01:00
committed by GitHub
parent 48fbca6b96
commit e0e4dd508c
9 changed files with 386 additions and 5 deletions

View File

@@ -6,6 +6,10 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LibUsbDotNet" Version="2.2.29" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NHSE.Core\NHSE.Core.csproj" />
</ItemGroup>

View File

@@ -9,7 +9,7 @@ namespace NHSE.Injection
public static class SwitchCommand
{
private static readonly Encoding Encoder = Encoding.UTF8;
private static byte[] Encode(string command) => Encoder.GetBytes(command + "\r\n");
private static byte[] Encode(string command, bool addrn = true) => Encoder.GetBytes(addrn ? command + "\r\n" : command);
/// <summary>
/// Removes the virtual controller from the bot. Allows physical controllers to control manually.
@@ -66,5 +66,13 @@ public static class SwitchCommand
/// <param name="data">Data to write</param>
/// <returns>Encoded command bytes</returns>
public static byte[] Poke(uint offset, byte[] data) => Encode($"poke 0x{offset:X8} 0x{string.Concat(data.Select(z => $"{z:X2}"))}");
/// <summary>
/// (Without return) Requests the Bot to send <see cref="count"/> bytes from <see cref="offset"/>.
/// </summary>
/// <param name="offset">Address of the data</param>
/// <param name="count">Amount of bytes</param>
/// <returns>Encoded command bytes</returns>
public static byte[] PeekRaw(uint offset, int count) => Encode($"peek 0x{offset:X8} {count}", false);
}
}

View File

@@ -0,0 +1,164 @@
using System;
using System.Threading;
using LibUsbDotNet;
using LibUsbDotNet.Main;
namespace NHSE.Injection
{
public class USBBot : IRAMReadWriter
{
private UsbDevice? SwDevice;
private UsbEndpointReader? reader;
private UsbEndpointWriter? writer;
public bool Connected { get; private set; }
private readonly object _sync = new object();
public bool Connect()
{
lock (_sync)
{
// Find and open the usb device.
//SwDevice = UsbDevice.OpenUsbDevice(SwFinder);
foreach (UsbRegistry ur in UsbDevice.AllDevices)
{
if (ur.Vid == 1406 && ur.Pid == 12288)
SwDevice = ur.Device;
}
//SwDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
// If the device is open and ready
if (SwDevice == null)
{
throw new Exception("Device Not Found.");
}
if (SwDevice.IsOpen)
SwDevice.Close();
SwDevice.Open();
if (SwDevice is IUsbDevice wholeUsbDevice)
{
// This is a "whole" USB device. Before it can be used,
// the desired configuration and interface must be selected.
// Select config #1
wholeUsbDevice.SetConfiguration(1);
// Claim interface #0.
bool resagain = wholeUsbDevice.ClaimInterface(0);
if (!resagain)
{
wholeUsbDevice.ReleaseInterface(0);
wholeUsbDevice.ClaimInterface(0);
}
}
else
{
Disconnect();
throw new Exception("Device is using WinUSB driver. Use libusbK and create a filter");
}
// open read write endpoints 1.
reader = SwDevice.OpenEndpointReader(ReadEndpointID.Ep01);
writer = SwDevice.OpenEndpointWriter(WriteEndpointID.Ep01);
Connected = true;
return true;
}
}
public void Disconnect()
{
lock (_sync)
{
if (SwDevice != null)
{
if (SwDevice.IsOpen)
{
IUsbDevice? wholeUsbDevice = SwDevice as IUsbDevice;
wholeUsbDevice?.ReleaseInterface(0);
SwDevice.Close();
}
}
reader?.Dispose();
writer?.Dispose();
Connected = false;
}
}
private int ReadInternal(byte[] buffer)
{
byte[] sizeOfReturn = new byte[4];
//read size, no error checking as of yet, should be the required 368 bytes
if (reader == null)
throw new Exception("USB writer is null, you may have disconnected the device during previous function");
reader.Read(sizeOfReturn, 5000, out _);
//read stack
reader.Read(buffer, 5000, out var lenVal);
return lenVal;
}
private int SendInternal(byte[] buffer)
{
if (writer == null)
throw new Exception("USB writer is null, you may have disconnected the device during previous function");
uint pack = (uint)buffer.Length + 2;
var ec = writer.Write(BitConverter.GetBytes(pack), 2000, out _);
if (ec != ErrorCode.None)
{
Disconnect();
throw new Exception(UsbDevice.LastErrorString);
}
ec = writer.Write(buffer, 2000, out var l);
if (ec != ErrorCode.None)
{
Disconnect();
throw new Exception(UsbDevice.LastErrorString);
}
return l;
}
public int Read(byte[] buffer)
{
lock (_sync)
{
return ReadInternal(buffer);
}
}
public byte[] ReadBytes(uint offset, int length)
{
lock (_sync)
{
var cmd = SwitchCommand.PeekRaw(offset, length);
SendInternal(cmd);
// give it time to push data back
Thread.Sleep((length / 256) + 100);
var buffer = new byte[length];
var _ = ReadInternal(buffer);
//return Decoder.ConvertHexByteStringToBytes(buffer);
return buffer;
}
}
public void WriteBytes(byte[] data, uint offset)
{
lock (_sync)
{
SendInternal(SwitchCommand.Poke(offset, data));
// give it time to push data back
Thread.Sleep((data.Length / 256) + 100);
}
}
}
}

View File

@@ -20,6 +20,10 @@ public static void Initialize(string path, string[] itemNames)
ItemNames = itemNames;
//create items folder if not exist
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
var files = Directory.EnumerateFiles(path, "*.png", SearchOption.AllDirectories);
foreach (var f in files)
{

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net46;netcoreapp3.1</TargetFrameworks>

View File

@@ -111,9 +111,12 @@ static void AfterWrite(InjectionResult r)
var sb = new SysBotController(InjectionType.Pouch);
var pockInject = new PocketInjector(ItemArray.Items, sb.Bot);
var ai = new AutoInjector(pockInject, AfterRead, AfterWrite);
var ub = new USBBotController();
var pockInjectUSB = new PocketInjector(ItemArray.Items, ub.Bot);
var aiUSB = new AutoInjector(pockInjectUSB, AfterRead, AfterWrite);
ItemGrid.ItemChanged = () => ai.Write();
var sysbot = new SysBotUI(ai, sb);
var sysbot = new SysBotUI(ai, sb, aiUSB, ub);
sysbot.Show();
}
}

View File

@@ -43,7 +43,13 @@ private void InitializeComponent()
this.B_ReadCurrent = new System.Windows.Forms.Button();
this.B_WriteCurrent = new System.Windows.Forms.Button();
this.TIM_Interval = new System.Windows.Forms.Timer(this.components);
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.ReadUSB = new System.Windows.Forms.Button();
this.WriteUSB = new System.Windows.Forms.Button();
this.L_OffsetUSB = new System.Windows.Forms.Label();
this.RamOffsetUSB = new System.Windows.Forms.TextBox();
this.GB_Inject.SuspendLayout();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// B_Connect
@@ -188,11 +194,65 @@ private void InitializeComponent()
//
this.TIM_Interval.Interval = 5000;
//
// groupBox1
//
this.groupBox1.Controls.Add(this.RamOffsetUSB);
this.groupBox1.Controls.Add(this.L_OffsetUSB);
this.groupBox1.Controls.Add(this.WriteUSB);
this.groupBox1.Controls.Add(this.ReadUSB);
this.groupBox1.Location = new System.Drawing.Point(16, 191);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(149, 75);
this.groupBox1.TabIndex = 14;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "USB";
//
// ReadUSB
//
this.ReadUSB.Location = new System.Drawing.Point(6, 46);
this.ReadUSB.Name = "ReadUSB";
this.ReadUSB.Size = new System.Drawing.Size(68, 23);
this.ReadUSB.TabIndex = 0;
this.ReadUSB.Text = "Read USB";
this.ReadUSB.UseVisualStyleBackColor = true;
this.ReadUSB.Click += new System.EventHandler(this.ReadUSB_Click);
//
// WriteUSB
//
this.WriteUSB.Location = new System.Drawing.Point(74, 46);
this.WriteUSB.Name = "WriteUSB";
this.WriteUSB.Size = new System.Drawing.Size(69, 23);
this.WriteUSB.TabIndex = 1;
this.WriteUSB.Text = "Write USB";
this.WriteUSB.UseVisualStyleBackColor = true;
this.WriteUSB.Click += new System.EventHandler(this.WriteUSB_Click);
//
// L_OffsetUSB
//
this.L_OffsetUSB.Location = new System.Drawing.Point(3, 24);
this.L_OffsetUSB.Name = "L_OffsetUSB";
this.L_OffsetUSB.Size = new System.Drawing.Size(63, 20);
this.L_OffsetUSB.TabIndex = 20;
this.L_OffsetUSB.Text = "Offset:";
this.L_OffsetUSB.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// RamOffsetUSB
//
this.RamOffsetUSB.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.RamOffsetUSB.Location = new System.Drawing.Point(72, 24);
this.RamOffsetUSB.MaxLength = 8;
this.RamOffsetUSB.Name = "RamOffsetUSB";
this.RamOffsetUSB.Size = new System.Drawing.Size(63, 20);
this.RamOffsetUSB.TabIndex = 24;
this.RamOffsetUSB.Text = "AC4723D0";
this.RamOffsetUSB.TextChanged += new System.EventHandler(this.RamOffsetUSB_TextChanged);
//
// SysBotUI
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(184, 197);
this.ClientSize = new System.Drawing.Size(184, 278);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.GB_Inject);
this.Controls.Add(this.B_Connect);
this.Controls.Add(this.L_Port);
@@ -209,6 +269,8 @@ private void InitializeComponent()
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SysBotUI_FormClosing);
this.GB_Inject.ResumeLayout(false);
this.GB_Inject.PerformLayout();
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@@ -230,5 +292,10 @@ private void InitializeComponent()
private System.Windows.Forms.CheckBox CHK_AutoRead;
private System.Windows.Forms.Timer TIM_Interval;
private System.Windows.Forms.CheckBox CHK_Validate;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Button ReadUSB;
private System.Windows.Forms.Button WriteUSB;
private System.Windows.Forms.TextBox RamOffsetUSB;
private System.Windows.Forms.Label L_OffsetUSB;
}
}

View File

@@ -9,13 +9,17 @@ public partial class SysBotUI : Form
{
private readonly AutoInjector Injector;
private readonly SysBotController Bot;
private readonly AutoInjector InjectorUSB;
private readonly USBBotController BotUSB;
public SysBotUI(AutoInjector injector, SysBotController c)
public SysBotUI(AutoInjector injector, SysBotController c, AutoInjector injectorUSB, USBBotController b)
{
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
Bot = c;
Injector = injector;
BotUSB = b;
InjectorUSB = injectorUSB;
var offset = Bot.GetDefaultOffset();
Injector.SetWriteOffset(offset);
@@ -122,5 +126,79 @@ private void RamOffset_TextChanged(object sender, EventArgs e)
Injector.SetWriteOffset(offset);
}
private void ReadUSB_Click(object sender, EventArgs e)
{
if (!BotUSB.Connect())
return;
var offset = StringUtil.GetHexValue(RamOffsetUSB.Text);
if (offset == 0)
{
WinFormsUtil.Error(MessageStrings.MsgInvalidHexValue);
return;
}
InjectorUSB.SetWriteOffset(offset);
try
{
var result = InjectorUSB.Read(true);
if (result == InjectionResult.Success)
return;
WinFormsUtil.Alert(result.ToString());
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
{
WinFormsUtil.Error(ex.Message);
}
BotUSB.Disconnect();
}
private void WriteUSB_Click(object sender, EventArgs e)
{
if (!BotUSB.Connect())
return;
var offset = StringUtil.GetHexValue(RamOffsetUSB.Text);
if (offset == 0)
{
WinFormsUtil.Error(MessageStrings.MsgInvalidHexValue);
return;
}
InjectorUSB.SetWriteOffset(offset);
try
{
var result = InjectorUSB.Write(true);
if (result == InjectionResult.Success)
return;
WinFormsUtil.Alert(result.ToString());
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
{
WinFormsUtil.Error(ex.Message);
}
BotUSB.Disconnect();
}
private void RamOffsetUSB_TextChanged(object sender, EventArgs e)
{
var offset = StringUtil.GetHexValue(RamOffsetUSB.Text);
if (offset == 0)
{
WinFormsUtil.Error(MessageStrings.MsgInvalidHexValue);
return;
}
Injector.SetWriteOffset(offset);
}
}
}

View File

@@ -0,0 +1,53 @@
using System;
using NHSE.Injection;
namespace NHSE.WinForms
{
public class USBBotController
{
public readonly USBBot Bot = new USBBot();
public bool Connect()
{
try
{
return Bot.Connect();
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
{
WinFormsUtil.Error(ex.Message);
return false;
}
}
public void Disconnect()
{
Bot.Disconnect();
}
//todo: this
//public uint GetDefaultOffset()
//{
// return Settings.Default.SysBotPouchOffset;
//}
//public void PopPrompt()
//{
//}
public void WriteBytes(byte[] data, uint offset)
{
Bot.WriteBytes(data, offset);
//SetOffset(offset);
}
public byte[] ReadBytes(uint offset, int length)
{
var result = Bot.ReadBytes(offset, length);
//SetOffset(offset);
return result;
}
}
}