Skip to content

Instantly share code, notes, and snippets.

@slodge
Created December 4, 2012 22:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slodge/4209727 to your computer and use it in GitHub Desktop.
Save slodge/4209727 to your computer and use it in GitHub Desktop.
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