using System; using System.Collections.Generic; using System.Text; using LibUsbDotNet; using LibUsbDotNet.Main; using Salamax.Logging; namespace Salamax { public class SilverlinkCable : USBDevice { private UsbDevice _device = null; private UsbEndpointReader _reader = null; private UsbEndpointWriter _writer = null; private Queue> _packets = new Queue>(); private List _packetBuffer = new List(); public event EventHandler ReceivedStaticDataRequest; public event EventHandler ReceivedChallenge1; public event EventHandler ReceivedChallenge2; public override bool IsConnected { get { return (_device != null && _device.IsOpen); } } public override void Find() { bool wasValid = (_device != null && _device.IsOpen); //Find the silverlink cable bool found = _FindDevice(); if (found) { if (wasValid) _reader.Device.Close(); if (!wasValid) { Logger.WriteLine("Silverlink cable found, initializing...", Logger.Type.Information); //Set configuration 1 int transferred; var setup = new UsbSetupPacket(0x00, 0x09, 0x0001, 0x0000, 0x0000); if (!_device.ControlTransfer(ref setup, IntPtr.Zero, 0, out transferred)) Logger.WriteLine("Failed to set silverlink cable configuration.", Logger.Type.Error); //Set up the incoming and outgoing bulk pipes _reader = _device.OpenEndpointReader(ReadEndpointID.Ep01, 0x40, EndpointType.Bulk); _reader.DataReceivedEnabled = true; _reader.DataReceived += _reader_DataReceived; _writer = _device.OpenEndpointWriter(WriteEndpointID.Ep02, EndpointType.Bulk); Logger.WriteLine("Silverlink cable initialized.", Logger.Type.Information); } } else if (_device != null) { _device = null; Logger.WriteLine("Silverlink cable disconnected.", Logger.Type.Warning); } } public override void Disconnect() { if (_device != null && _device.IsOpen) { _device.Close(); } } public int ForwardData(byte type, byte[] data, int length) { var buffer = new byte[length + 3]; int ret; buffer[0] = type; buffer[1] = (byte)(length & 0xFF); buffer[2] = (byte)((length >> 8) & 0xFF); for (int i = 0; i < length; i++) buffer[i + 3] = data[i]; Logger.WriteLine("Forwarding data to calculator...", Logger.Type.Information); if (_writer.Transfer(buffer, 0, buffer.Length, 5000, out ret) == ErrorCode.Success) { string msg = "Data forwarded to calculator: "; for (int i = 0; i < length; i++) msg += data[i].ToString("X2") + " "; if (length + 3 != ret) Logger.WriteLine(String.Format("Sent {0} bytes, but only {1} bytes transferred!", length + 3, ret), Logger.Type.Warning); Logger.WriteLine(msg, Logger.Type.Information); } else Logger.WriteLine("Forwarding data failed.", Logger.Type.Error); return ret; } private bool _FindDevice() { bool ret = false; foreach (object reg in LibUsbDotNet.LibUsb.LibUsbRegistry.DeviceList) { if (reg.GetType() == typeof(LibUsbDotNet.LibUsb.LibUsbRegistry)) { var usb = reg as LibUsbDotNet.LibUsb.LibUsbRegistry; if (usb.Vid == 0x0451 && usb.Pid == 0xE001) { _device = usb.Device; ret = true; break; } } } return ret; } private void _reader_DataReceived(object sender, EndpointDataEventArgs e) { string msg = "Raw received data from calculator: "; for (int i = 0; i < e.Count; i++) { _packetBuffer.Add(e.Buffer[i]); msg += e.Buffer[i].ToString("X2") + " "; } Logger.WriteLine(msg, Logger.Type.Information); if (_packetBuffer.Count >= 3) { //We might have a complete packet, check the length int length = _packetBuffer[1] | (_packetBuffer[2] << 8); if (_packetBuffer.Count >= (length + 3)) { //We have a complete packet, rip it out //First rip out the header byte type = _packetBuffer[0]; _packetBuffer.RemoveAt(0); _packetBuffer.RemoveAt(0); _packetBuffer.RemoveAt(0); //Now get the data out var data = new byte[length]; for (int i = 0; i < length; i++) { data[i] = _packetBuffer[0]; _packetBuffer.RemoveAt(0); } //Save this in our queue of packets to process lock (_packets) { _packets.Enqueue(new KeyValuePair(type, data)); } _HandlePackets(); } } } private void _HandlePackets() { KeyValuePair packet = new KeyValuePair(); bool retrieved = false; lock (_packets) { if (_packets.Count > 0) { packet = _packets.Dequeue(); retrieved = true; } } if (retrieved) { retrieved = false; //Display it! string msg = String.Format("Received calculator packet, type {0}, data: ", packet.Key.ToString("X2")); for (int i = 0; i < packet.Value.Length; i++) msg += packet.Value[i].ToString("X2") + " "; Logger.WriteLine(msg.Trim(), Logger.Type.Information); //Now handle it if (packet.Key == 0x81) { if (ReceivedStaticDataRequest != null) ReceivedStaticDataRequest(this, EventArgs.Empty); } else if (packet.Key == 0x82) { if (ReceivedChallenge1 != null) ReceivedChallenge1(this, new ChallengeEventArgs(packet.Value)); } else if (packet.Key == 0x87) { if (ReceivedChallenge2 != null) ReceivedChallenge2(this, new ChallengeEventArgs(packet.Value)); } else if (packet.Key == 0x90) { Logger.WriteLine("Calculator has been successfully initialized as an Xbox 360 controller.", Logger.Type.Information); } } } } }