Created
December 4, 2012 22:42
-
-
Save slodge/4209727 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Drawing; | |
using MonoTouch.Foundation; | |
using MonoTouch.UIKit; | |
using MonoTouch.ExternalAccessory; | |
using System.Collections.Generic; | |
namespace ExtAcc | |
{ | |
public class AccessoryAdapter : IDisposable | |
{ | |
private readonly string protocol; | |
private NSObject accessoryConnectedObserver; | |
private bool accessoryConnected; | |
private EASession session; | |
private EAAccessory accessory; | |
public AccessoryAdapter (string aProtocol) | |
{ | |
protocol = aProtocol; | |
Initialize(); | |
} | |
public bool IsAccessoryConnected | |
{ | |
get { return accessoryConnected; } | |
} | |
private void Initialize() | |
{ | |
accessoryConnectedObserver = NSNotificationCenter.DefaultCenter.AddObserver(new NSString("EAAccessoryDidConnectNotification"), AccessoryConnected); | |
EAAccessoryManager.SharedAccessoryManager.RegisterForLocalNotifications(); | |
} | |
private void AccessoryConnected(NSNotification aNotification) | |
{ | |
#if DEBUG | |
Console.WriteLine("AccessoryAdapter - An accessory was connected"); | |
#endif | |
if (!accessoryConnected) | |
{ | |
ConnectToAccessory(); | |
} | |
HandleConnected(); | |
} | |
private void AccessoryDisconnected(object aSource, EventArgs aEventArgs) | |
{ | |
#if DEBUG | |
Console.WriteLine("AccessoryAdapter - The accessory was disconnected"); | |
#endif | |
HandleDisconnected(); | |
try | |
{ | |
if (session != null) | |
{ | |
if (session.InputStream != null) | |
{ | |
session.InputStream.Close(); | |
session.InputStream.Unschedule(NSRunLoop.Current, "kCFRunLoopDefaultMode"); | |
session.InputStream.OnEvent -= DataReceived; | |
} | |
session.Dispose(); | |
session = null; | |
} | |
if (accessory != null) | |
{ | |
accessory.Disconnected -= AccessoryDisconnected; | |
accessory.Dispose(); | |
accessory = null; | |
} | |
accessoryConnected = false; | |
} | |
catch (Exception exc) | |
{ | |
Console.WriteLine("An unexpected error occurred disconnecting from the accessory",exc); | |
} | |
finally | |
{ | |
accessoryConnected = false; | |
} | |
} | |
public void Dispose () | |
{ | |
if (accessoryConnected) | |
{ | |
AccessoryDisconnected(null,null); | |
} | |
if (accessoryConnectedObserver != null) NSNotificationCenter.DefaultCenter.RemoveObserver(accessoryConnectedObserver); | |
EAAccessoryManager.SharedAccessoryManager.UnregisterForLocalNotifications(); | |
} | |
private void ConnectToAccessory() | |
{ | |
// Make sure this only happens on one thread. | |
lock(protocol) | |
{ | |
if (!accessoryConnected) | |
{ | |
#if DEBUG | |
Console.WriteLine("AccessoryAdapter - Trying to connect to the accessory"); | |
#endif | |
try | |
{ | |
EAAccessory[] accessories = EAAccessoryManager.SharedAccessoryManager.ConnectedAccessories; | |
EAAccessory accessory = null; | |
//EASession session = null; | |
if (accessories == null || accessories.Length == 0) | |
{ | |
#if DEBUG | |
Console.WriteLine("... No accessories connected"); | |
#endif | |
return; | |
} | |
for (int a=0;a<accessories.Length && accessory == null;a++) | |
{ | |
var vAccessory = accessories[a]; | |
#if DEBUG | |
Console.WriteLine("... Checking accessory: {0} {1}",vAccessory.Name, vAccessory.ModelNumber); | |
#endif | |
for (int i=0;i<vAccessory.ProtocolStrings.Length && accessory == null;i++) | |
{ | |
string vProtocol = vAccessory.ProtocolStrings[i]; | |
#if DEBUG | |
Console.WriteLine("...... Supports protocol: {0}",vProtocol); | |
#endif | |
if (protocol.Equals(vProtocol)) | |
{ | |
#if DEBUG | |
Console.WriteLine("...... Protocol found"); | |
#endif | |
accessory = vAccessory; | |
} | |
} | |
} | |
if (accessory != null) | |
{ | |
accessoryConnected = true; | |
accessory.Disconnected += AccessoryDisconnected; | |
#if DEBUG | |
Console.WriteLine("... Creating session"); | |
#endif | |
session = new EASession(accessory, protocol); | |
#if DEBUG | |
Console.WriteLine("... Opening input stream"); | |
#endif | |
session.InputStream.OnEvent += DataReceived; | |
session.InputStream.Schedule(NSRunLoop.Current, "kCFRunLoopDefaultMode"); | |
session.InputStream.Open(); | |
session.OutputStream.OnEvent += OutputReceived; | |
session.OutputStream.Schedule(NSRunLoop.Current, "kCFRunLoopDefaultMode"); | |
session.OutputStream.Open(); | |
SendColor(); | |
} | |
} | |
catch (Exception exc) | |
{ | |
Console.WriteLine("An unexpected error occured trying to connect to the accessory.",exc); | |
} | |
} | |
} | |
} | |
void OutputReceived (object sender, NSStreamEventArgs e) | |
{ | |
} | |
public virtual void DataReceived (object sender, NSStreamEventArgs e) | |
{ | |
// Override this method if you need to do something when data is received | |
} | |
public virtual void HandleConnected () | |
{ | |
// Override this method if you need to do something when the accessory is connected | |
} | |
public virtual void HandleDisconnected () | |
{ | |
// Override this method if you need to do something when the accessory is disconnected | |
} | |
public void SendColor () | |
{ | |
byte checksum = 0; | |
byte[] data = new byte[10]; | |
data[0] = 0xFF; //SOP1 | |
data[1] = 0xFF; //SOP2 | |
data[2] = 0x02; //DID | |
checksum += data[2]; | |
data[3] = 0x20; //CID | |
checksum += data[3]; | |
data[4] = 0x01; //SEQ | |
checksum += data[4]; | |
data[5] = 0x04; //DLEN | |
checksum += data[5]; | |
data[6] = 0; // (uint8_t)(arc4random() % 256); //RED | |
checksum += data[6]; | |
data[7] = 255; //(uint8_t)(arc4random() % 256); //GREEN | |
checksum += data[7]; | |
data[8] = 0; // (uint8_t)(arc4random() % 256); //BLUE | |
checksum += data[8]; | |
data[9] = (byte)~checksum; | |
WriteBytes(data); | |
} | |
private void WriteBytes(byte[] toSend) | |
{ | |
int sent = 0; | |
var stillToSend = toSend; | |
while (session.OutputStream.HasSpaceAvailable() && stillToSend.Length > 0) | |
{ | |
var bytesWritten = session.OutputStream.Write(toSend, (uint)stillToSend.Length); // [[_session outputStream] write:[_writeData bytes] maxLength:[_writeData length]]; | |
if (bytesWritten == -1) | |
{ | |
Console.WriteLine(@"write error"); | |
break; | |
} | |
else if (bytesWritten > 0) | |
{ | |
if (bytesWritten == stillToSend.Length) | |
break; | |
var temp = new List<byte>(); | |
for (var i=bytesWritten; i<stillToSend.Length; i++) | |
{ | |
temp.Add(stillToSend[i]); | |
} | |
stillToSend = temp.ToArray(); | |
//[_writeData replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0]; | |
} | |
} | |
} | |
} | |
public partial class ExtAccViewController : UIViewController | |
{ | |
private NSObject _accessoryConnectedObserver; | |
private AccessoryAdapter _adapter; | |
static bool UserInterfaceIdiomIsPhone { | |
get { return UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone; } | |
} | |
public ExtAccViewController () | |
: base (UserInterfaceIdiomIsPhone ? "ExtAccViewController_iPhone" : "ExtAccViewController_iPad", null) | |
{ | |
} | |
public override void DidReceiveMemoryWarning () | |
{ | |
// Releases the view if it doesn't have a superview. | |
base.DidReceiveMemoryWarning (); | |
// Release any cached data, images, etc that aren't in use. | |
} | |
public override void ViewDidLoad () | |
{ | |
base.ViewDidLoad (); | |
// Perform any additional setup after loading the view, typically from a nib. | |
} | |
public override void ViewDidAppear (bool animated) | |
{ | |
base.ViewDidAppear (animated); | |
_adapter = new AccessoryAdapter("com.orbotix.robotprotocol"); | |
//_accessoryConnectedObserver = NSNotificationCenter.DefaultCenter.AddObserver(new NSString("EAAccessoryDidConnectNotification"), AccessoryConnected); | |
//EAAccessoryManager.SharedAccessoryManager.RegisterForLocalNotifications(); | |
} | |
public override void ViewDidDisappear (bool animated) | |
{ | |
base.ViewDidDisappear (animated); | |
_adapter.Dispose(); | |
} | |
public override void ViewDidUnload () | |
{ | |
base.ViewDidUnload (); | |
// Clear any references to subviews of the main view in order to | |
// allow the Garbage Collector to collect them sooner. | |
// | |
// e.g. myOutlet.Dispose (); myOutlet = null; | |
ReleaseDesignerOutlets (); | |
} | |
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation) | |
{ | |
// Return true for supported orientations | |
if (UserInterfaceIdiomIsPhone) { | |
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown); | |
} else { | |
return true; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment