Brokenithm-iOS/Brokenithm-Evolved-iOS/Program.cs

308 lines
12 KiB
C#

using iMobileDevice;
using iMobileDevice.iDevice;
using System;
using System.Collections.Generic;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Brokenithm_Evolved_iOS
{
class Program
{
public static Dictionary<string, iDeviceHandle> device_map = new Dictionary<string, iDeviceHandle>();
public static Dictionary<string, iDeviceConnectionHandle> connection_map = new Dictionary<string, iDeviceConnectionHandle>();
public static IiDeviceApi idevice;
public static MemoryMappedFile sharedBuffer;
public static MemoryMappedViewAccessor sharedBufferAccessor;
public static bool exiting = false;
public static iDeviceEventCallBack _eventCallback;
static void Main(string[] args)
{
Console.Title = "Brokenithm-Evolved-iOS";
Console.WriteLine("=================================================");
Console.WriteLine("= Brokenithm-Evolved-iOS: =");
Console.WriteLine("= Brokenithm with full IO and USB connection =");
Console.WriteLine("= v0.3 by esterTion =");
Console.WriteLine("= Original: thebit.link =");
Console.WriteLine("=================================================");
Console.WriteLine("");
NativeLibraries.Load();
idevice = LibiMobileDevice.Instance.iDevice;
iDeviceError status;
_eventCallback = new iDeviceEventCallBack(eventCallback);
status = LibiMobileDevice.Instance.iDevice.idevice_event_subscribe(_eventCallback, IntPtr.Zero);
MemoryMappedFileSecurity CustomSecurity = new MemoryMappedFileSecurity();
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
var acct = sid.Translate(typeof(NTAccount)) as NTAccount;
CustomSecurity.AddAccessRule(new System.Security.AccessControl.AccessRule<MemoryMappedFileRights>(acct.ToString(), MemoryMappedFileRights.FullControl, System.Security.AccessControl.AccessControlType.Allow));
sharedBuffer = MemoryMappedFile.CreateOrOpen("Local\\BROKENITHM_SHARED_BUFFER", 1024, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, CustomSecurity, System.IO.HandleInheritability.Inheritable);
sharedBufferAccessor = sharedBuffer.CreateViewAccessor();
{
Thread ledThread = new Thread(new ThreadStart(outputLed));
ledThread.Start();
}
Console.WriteLine("Waiting for device...");
while (Console.ReadKey().Key != ConsoleKey.Q) { }
exiting = true;
}
public static void eventCallback(ref iDeviceEvent e, IntPtr user_data)
{
iDeviceError status;
string udid = e.udidString;
switch (e.@event)
{
case iDeviceEventType.DeviceAdd:
{
Console.WriteLine(string.Format("device add\tudid: {0}", udid));
if (device_map.ContainsKey(udid))
{
return;
}
iDeviceHandle device;
status = idevice.idevice_new(out device, e.udidString);
if (status != iDeviceError.Success)
{
Console.WriteLine("Create device failed: {0}", status);
return;
}
device_map[udid] = device;
Thread thread = new Thread(new ParameterizedThreadStart(connectDevice));
thread.Start(udid);
break;
}
case iDeviceEventType.DevicePaired:
{
Console.WriteLine(string.Format("device paired\tudid: {0}", udid));
break;
}
case iDeviceEventType.DeviceRemove:
{
Console.WriteLine(string.Format("device remove\tudid: {0}", udid));
if (device_map.ContainsKey(udid))
{
iDeviceHandle device = device_map[udid];
device.Dispose();
device_map.Remove(udid);
}
break;
}
}
}
public static void connectDevice(object arg)
{
string udid = (string)arg;
if (!device_map.ContainsKey(udid))
{
return;
}
iDeviceHandle device = device_map[udid];
iDeviceConnectionHandle conn;
iDeviceError status;
status = idevice.idevice_connect(device, 24864, out conn);
if (status != iDeviceError.Success)
{
//Console.WriteLine(string.Format("connect failed: {0}", status));
Thread.Sleep(1000);
Thread thread = new Thread(new ParameterizedThreadStart(connectDevice));
thread.Start(udid);
return;
}
byte[] buf = new byte[256];
uint read = 0;
status = idevice.idevice_connection_receive(conn, buf, 4, ref read);
if (status != iDeviceError.Success)
{
Console.WriteLine(string.Format("receive data failed: {0}", status));
return;
}
if (
buf[0] != 3 ||
buf[1] != 'W' ||
buf[2] != 'E' ||
buf[3] != 'L'
)
{
// welcome message
Console.WriteLine("received invalid data");
conn.Dispose();
return;
}
Console.WriteLine("connected to device");
connection_map[udid] = conn;
{
Thread thread = new Thread(new ParameterizedThreadStart(readInputFromDevice));
thread.Start(udid);
}
return;
}
public static void readInputFromDevice(object arg)
{
string udid = (string)arg;
if (!connection_map.ContainsKey(udid))
{
return;
}
iDeviceConnectionHandle conn = connection_map[udid];
iDeviceError status;
bool airEnabled = true;
byte[] buf = new byte[256];
uint read = 0;
while (true)
{
if (exiting) break;
status = idevice.idevice_connection_receive_timeout(conn, buf, 1, ref read, 5);
if (status != iDeviceError.Success)
{
if (status == iDeviceError.Timeout)
{
continue;
}
break;
}
byte len = buf[0];
status = idevice.idevice_connection_receive_timeout(conn, buf, len, ref read, 5);
if (status != iDeviceError.Success)
{
break;
}
if (len >= 3+6+32 &&
buf[0] == 'I' &&
buf[1] == 'N' &&
buf[2] == 'P')
{
// key input
if (airEnabled)
{
sharedBufferAccessor.WriteArray<byte>(0, buf, 3, 6 + 32);
}
else
{
sharedBufferAccessor.WriteArray<byte>(6, buf, 3 + 6, 32);
}
if (len > 3 + 6 + 32)
{
sharedBufferAccessor.WriteArray<byte>(6+32+96, buf, 3+6+32, len - (3 + 6 + 32));
}
}
else if (len >= 4 &&
buf[0] == 'A' &&
buf[1] == 'I' &&
buf[2] == 'R')
{
// air input control
airEnabled = buf[3] != 0;
Console.WriteLine(string.Format("Air input {0}", airEnabled ? "enabled" : "disabled"));
}
else if (len >= 4 &&
buf[0] == 'F' &&
buf[1] == 'N' &&
buf[2] == 'C')
{
// function key
if (buf[3] == (byte)BNI_FUNCTION_KEYS.COIN)
{
sharedBufferAccessor.Write(6 + 32 + 96 + 2, 1);
}
else if (buf[3] == (byte)BNI_FUNCTION_KEYS.CARD)
{
sharedBufferAccessor.Write(6 + 32 + 96 + 3, 1);
}
}
else
{
if (len >= 3)
{
StringBuilder sb = new StringBuilder();
sb.Append((char)buf[0]);
sb.Append((char)buf[1]);
sb.Append((char)buf[2]);
Console.WriteLine(string.Format("unknown packet: {0}", sb.ToString()));
}
else
{
Console.WriteLine("unknown packet");
}
}
}
conn.Dispose();
connection_map.Remove(udid);
Console.WriteLine("disconnected");
if (exiting) return;
Thread.Sleep(1000);
{
Thread thread = new Thread(new ParameterizedThreadStart(connectDevice));
thread.Start(udid);
}
}
enum BNI_FUNCTION_KEYS {
COIN = 1,
CARD
};
private static byte[] prevLedRgb = new byte[32 * 3];
private static int skipCount = 0;
public static void outputLed()
{
while (true)
{
if (exiting) break;
byte[] ledRgb = new byte[32 * 3];
sharedBufferAccessor.ReadArray<byte>(6 + 32, ledRgb, 0, 32 * 3);
bool same = true;
for (int i = 0; i < 32 * 3; i++)
{
if (ledRgb[i] != prevLedRgb[i])
{
same = false;
break;
}
}
if (!same)
{
BroadcastLEDStatus(ledRgb);
prevLedRgb = ledRgb;
skipCount = 0;
}
else
{
if (++skipCount > 50)
{
BroadcastLEDStatus(prevLedRgb);
skipCount = 0;
}
}
Thread.Sleep(10);
}
}
public static void BroadcastLEDStatus(byte[] led)
{
uint sent = 0;
byte[] head = { 99, (byte)'L', (byte)'E', (byte)'D' };
foreach (var conn in connection_map)
{
try
{
idevice.idevice_connection_send(conn.Value, head, 4, ref sent);
idevice.idevice_connection_send(conn.Value, led, 96, ref sent);
}
catch (Exception e) { }
}
}
}
}