diff --git a/project/.gitignore b/project/.gitignore index fdb9cf7..e1bf752 100644 --- a/project/.gitignore +++ b/project/.gitignore @@ -1,11 +1,21 @@ /Temp /obj /library +/[Bb]in + *.csproj *.unityproj *.sln project.userprefs -/Assets/Myo/Scripts/Myo.NET -/Assets/Myo/Scripts/Myo.NET.meta /Assets/Plugins /Assets/Plugins.meta + +MyoUnityIOS/MyoUnityIOS.xcodeproject/*/xcuserdata/ +MyoUnityIOS/MyoUnityIOS.xcodeproject/xcuserdata/ +MyoUnityIOS/MyoUnityIOS/MyoKit.framework + +MyoUnityIOS/MyoUnityIOS.xcodeproj/xcuserdata +MyoUnityIOS/MyoUnityIOS.xcodeproj/project.xcworkspace/ +MyoUnityIOS/Build +ProjectSettings/ + diff --git a/project/Assets/Myo Samples/Box On A Stick.unity b/project/Assets/Myo Samples/Box On A Stick.unity index d502b9f..8f58df3 100644 --- a/project/Assets/Myo Samples/Box On A Stick.unity +++ b/project/Assets/Myo Samples/Box On A Stick.unity @@ -12,57 +12,70 @@ SceneSettings: backfaceThreshold: 100 --- !u!104 &2 RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 6 m_Fog: 0 m_FogColor: {r: .5, g: .5, b: .5, a: 1} m_FogMode: 3 m_FogDensity: .00999999978 m_LinearFogStart: 0 m_LinearFogEnd: 300 - m_AmbientLight: {r: .200000003, g: .200000003, b: .200000003, a: 1} + m_AmbientSkyColor: {r: .200000003, g: .200000003, b: .200000003, a: 1} + m_AmbientEquatorColor: {r: .200000003, g: .200000003, b: .200000003, a: 1} + m_AmbientGroundColor: {r: .200000003, g: .200000003, b: .200000003, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 m_SkyboxMaterial: {fileID: 0} m_HaloStrength: .5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 m_HaloTexture: {fileID: 0} - m_SpotCookie: {fileID: 0} - m_ObjectHideFlags: 0 + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} --- !u!127 &3 LevelGameManager: m_ObjectHideFlags: 0 --- !u!157 &4 LightmapSettings: m_ObjectHideFlags: 0 - m_LightProbes: {fileID: 0} - m_Lightmaps: [] + serializedVersion: 5 + m_GIWorkflowMode: 1 m_LightmapsMode: 1 - m_BakedColorSpace: 0 - m_UseDualLightmapsInForward: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_TemporalCoherenceThreshold: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 m_LightmapEditorSettings: - m_Resolution: 50 - m_LastUsedResolution: 0 + serializedVersion: 3 + m_Resolution: 1 + m_BakeResolution: 50 m_TextureWidth: 1024 m_TextureHeight: 1024 - m_BounceBoost: 1 - m_BounceIntensity: 1 - m_SkyLightColor: {r: .860000014, g: .930000007, b: 1, a: 1} - m_SkyLightIntensity: 0 - m_Quality: 0 - m_Bounces: 1 - m_FinalGatherRays: 1000 - m_FinalGatherContrastThreshold: .0500000007 - m_FinalGatherGradientThreshold: 0 - m_FinalGatherInterpolationPoints: 15 - m_AOAmount: 0 - m_AOMaxDistance: .100000001 - m_AOContrast: 1 - m_LODSurfaceMappingDistance: 1 - m_Padding: 0 + m_AOMaxDistance: 1 + m_Padding: 2 + m_CompAOExponent: 0 + m_LightmapParameters: {fileID: 0} m_TextureCompression: 0 - m_LockAtlas: 0 + m_FinalGather: 0 + m_FinalGatherRayCount: 1024 + m_LightmapSnapshot: {fileID: 0} + m_RuntimeCPUUsage: 25 --- !u!196 &5 NavMeshSettings: + serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: + serializedVersion: 2 agentRadius: .5 agentHeight: 2 agentSlope: 45 @@ -71,9 +84,9 @@ NavMeshSettings: maxJumpAcrossDistance: 0 accuratePlacement: 0 minRegionArea: 2 - widthInaccuracy: 16.666666 - heightInaccuracy: 10 - m_NavMesh: {fileID: 0} + cellSize: .166666657 + manualCellSize: 0 + m_NavMeshData: {fileID: 0} --- !u!1 &59334980 GameObject: m_ObjectHideFlags: 0 @@ -141,8 +154,12 @@ Camera: m_Bits: 4294967295 m_RenderingPath: -1 m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 m_HDR: 0 m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: .0219999999 + m_StereoMirrorMode: 0 --- !u!4 &59334985 Transform: m_ObjectHideFlags: 0 @@ -154,6 +171,7 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} + m_RootOrder: 2 --- !u!1 &312746764 GameObject: m_ObjectHideFlags: 0 @@ -182,6 +200,7 @@ Transform: m_Children: - {fileID: 2054326013} m_Father: {fileID: 0} + m_RootOrder: 1 --- !u!114 &312746766 MonoBehaviour: m_ObjectHideFlags: 0 @@ -217,10 +236,10 @@ Light: m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 971960788} m_Enabled: 1 - serializedVersion: 3 + serializedVersion: 6 m_Type: 2 m_Color: {r: 1, g: 1, b: 1, a: 1} - m_Intensity: 5 + m_Intensity: 10 m_Range: 12 m_SpotAngle: 30 m_CookieSize: 10 @@ -229,21 +248,18 @@ Light: m_Resolution: -1 m_Strength: 1 m_Bias: .0500000007 - m_Softness: 4 - m_SoftnessFade: 1 + m_NormalBias: .400000006 m_Cookie: {fileID: 0} m_DrawHalo: 0 - m_ActuallyLightmapped: 0 m_Flare: {fileID: 0} m_RenderMode: 0 m_CullingMask: serializedVersion: 2 m_Bits: 4294967295 m_Lightmapping: 1 - m_ShadowSamples: 1 + m_BounceIntensity: 1 m_ShadowRadius: 0 m_ShadowAngle: 0 - m_IndirectIntensity: 1 m_AreaSize: {x: 1, y: 1} --- !u!4 &971960790 Transform: @@ -256,6 +272,7 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} + m_RootOrder: 3 --- !u!1 &1015758529 GameObject: m_ObjectHideFlags: 0 @@ -283,7 +300,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 2d9dbd4fb92d94ec7b7c56eda32a02eb, type: 3} m_Name: m_EditorClassIdentifier: - myo: {fileID: 1201201557} + thalmicMyo: {fileID: 1201201558} --- !u!4 &1015758531 Transform: m_ObjectHideFlags: 0 @@ -295,6 +312,7 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} + m_RootOrder: 4 --- !u!1 &1036158881 GameObject: m_ObjectHideFlags: 0 @@ -314,7 +332,7 @@ GameObject: m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!23 &1036158882 -Renderer: +MeshRenderer: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} @@ -322,18 +340,21 @@ Renderer: m_Enabled: 1 m_CastShadows: 1 m_ReceiveShadows: 1 - m_LightmapIndex: 255 - m_LightmapTilingOffset: {x: 1, y: 1, z: 0, w: 0} m_Materials: - {fileID: 2100000, guid: 1f16471eaab1a45bcbf5dbfddc3894d7, type: 2} m_SubsetIndices: m_StaticBatchRoot: {fileID: 0} m_UseLightProbes: 0 - m_LightProbeAnchor: {fileID: 0} + m_ReflectionProbeUsage: 1 + m_ProbeAnchor: {fileID: 0} m_ScaleInLightmap: 1 - m_SortingLayer: 0 - m_SortingOrder: 0 + m_PreserveUVs: 0 + m_ImportantGI: 0 + m_AutoUVMaxDistance: .5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} m_SortingLayerID: 0 + m_SortingOrder: 0 --- !u!114 &1036158883 MonoBehaviour: m_ObjectHideFlags: 0 @@ -367,92 +388,17 @@ Transform: m_LocalScale: {x: 3.33333325, y: 3.33333325, z: .25} m_Children: [] m_Father: {fileID: 2054326013} ---- !u!1 &1110177953 -GameObject: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 100002, guid: 863250160b56e46dbb2d227833b7338a, type: 2} - m_PrefabInternal: {fileID: 1433290547} - serializedVersion: 4 - m_Component: - - 4: {fileID: 1110177954} - - 114: {fileID: 1110177955} - m_Layer: 0 - m_Name: One Myo - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1110177954 -Transform: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 400002, guid: 863250160b56e46dbb2d227833b7338a, type: 2} - m_PrefabInternal: {fileID: 1433290547} - m_GameObject: {fileID: 1110177953} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: - - {fileID: 1201201559} - m_Father: {fileID: 0} ---- !u!114 &1110177955 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 11400002, guid: 863250160b56e46dbb2d227833b7338a, - type: 2} - m_PrefabInternal: {fileID: 1433290547} - m_GameObject: {fileID: 1110177953} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: ab0b7b6ac98ab4b35b65cd9fa62c457f, type: 3} - m_Name: - m_EditorClassIdentifier: - pairingMethod: 0 - pairingMacAddress: - hubInitialized: 0 ---- !u!1 &1201201557 + m_RootOrder: 0 +--- !u!1 &1201201557 stripped GameObject: - m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 100000, guid: 863250160b56e46dbb2d227833b7338a, type: 2} m_PrefabInternal: {fileID: 1433290547} - serializedVersion: 4 - m_Component: - - 4: {fileID: 1201201559} - - 114: {fileID: 1201201558} - m_Layer: 0 - m_Name: Myo - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1201201558 +--- !u!114 &1201201558 stripped MonoBehaviour: - m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 11400000, guid: 863250160b56e46dbb2d227833b7338a, type: 2} m_PrefabInternal: {fileID: 1433290547} - m_GameObject: {fileID: 1201201557} - m_Enabled: 1 - m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 917262f8ecbe7423583085eb03acfbb0, type: 3} - m_Name: - m_EditorClassIdentifier: - rawQuaternion: {x: 0, y: 0, z: 0, w: 0} - accelerometer: {x: 0, y: 0, z: 0} - gyroscope: {x: 0, y: 0, z: 0} - pose: 65535 ---- !u!4 &1201201559 -Transform: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 400000, guid: 863250160b56e46dbb2d227833b7338a, type: 2} - m_PrefabInternal: {fileID: 1433290547} - m_GameObject: {fileID: 1201201557} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 1110177954} --- !u!1001 &1433290547 Prefab: m_ObjectHideFlags: 0 @@ -498,9 +444,7 @@ Prefab: objectReference: {fileID: 0} m_RemovedComponents: [] m_ParentPrefab: {fileID: 100100000, guid: 863250160b56e46dbb2d227833b7338a, type: 2} - m_RootGameObject: {fileID: 1110177953} m_IsPrefabParent: 0 - m_IsExploded: 1 --- !u!1 &2054326012 GameObject: m_ObjectHideFlags: 0 @@ -530,8 +474,9 @@ Transform: m_Children: - {fileID: 1036158885} m_Father: {fileID: 312746765} + m_RootOrder: 0 --- !u!23 &2054326014 -Renderer: +MeshRenderer: m_ObjectHideFlags: 0 m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} @@ -539,18 +484,21 @@ Renderer: m_Enabled: 1 m_CastShadows: 0 m_ReceiveShadows: 1 - m_LightmapIndex: 255 - m_LightmapTilingOffset: {x: 1, y: 1, z: 0, w: 0} m_Materials: - {fileID: 2100000, guid: 712d9dddf82ad42c5962a57b9da6065e, type: 2} m_SubsetIndices: m_StaticBatchRoot: {fileID: 0} m_UseLightProbes: 0 - m_LightProbeAnchor: {fileID: 0} + m_ReflectionProbeUsage: 1 + m_ProbeAnchor: {fileID: 0} m_ScaleInLightmap: 1 - m_SortingLayer: 0 - m_SortingOrder: 0 + m_PreserveUVs: 0 + m_ImportantGI: 0 + m_AutoUVMaxDistance: .5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} m_SortingLayerID: 0 + m_SortingOrder: 0 --- !u!33 &2054326016 MeshFilter: m_ObjectHideFlags: 0 diff --git a/project/Assets/Myo Samples/Scripts/ColorBoxByPose.cs b/project/Assets/Myo Samples/Scripts/ColorBoxByPose.cs index af5e7c1..dae5c4b 100644 --- a/project/Assets/Myo Samples/Scripts/ColorBoxByPose.cs +++ b/project/Assets/Myo Samples/Scripts/ColorBoxByPose.cs @@ -46,15 +46,15 @@ void Update () // Change material when wave in, wave out or double tap poses are made. } else if (thalmicMyo.pose == Pose.WaveIn) { - renderer.material = waveInMaterial; + GetComponent().material = waveInMaterial; ExtendUnlockAndNotifyUserAction (thalmicMyo); } else if (thalmicMyo.pose == Pose.WaveOut) { - renderer.material = waveOutMaterial; + GetComponent().material = waveOutMaterial; ExtendUnlockAndNotifyUserAction (thalmicMyo); } else if (thalmicMyo.pose == Pose.DoubleTap) { - renderer.material = doubleTapMaterial; + GetComponent().material = doubleTapMaterial; ExtendUnlockAndNotifyUserAction (thalmicMyo); } diff --git a/project/Assets/Myo Samples/Scripts/SampleSceneGUI.cs b/project/Assets/Myo Samples/Scripts/SampleSceneGUI.cs index b9c480c..b232dd7 100644 --- a/project/Assets/Myo Samples/Scripts/SampleSceneGUI.cs +++ b/project/Assets/Myo Samples/Scripts/SampleSceneGUI.cs @@ -3,46 +3,122 @@ // Draw simple instructions for sample scene. // Check to see if a Myo armband is paired. +using System.Collections.Generic; + + public class SampleSceneGUI : MonoBehaviour { // Myo game object to connect with. // This object must have a ThalmicMyo script attached. - public GameObject myo = null; + public ThalmicMyo thalmicMyo; + + int numConnectionsAllowed = 1; // Draw some basic instructions. void OnGUI () { - GUI.skin.label.fontSize = 20; + int fontSize = (int)(Screen.height * 0.03f); + int smallFontSize = fontSize / 2; + GUI.skin.button.fontSize = fontSize; + GUI.skin.label.fontSize = fontSize; + GUI.skin.textField.fontSize = fontSize; - ThalmicHub hub = ThalmicHub.instance; + GUILayout.BeginArea(new Rect(0,0,Screen.width, Screen.height)); - // Access the ThalmicMyo script attached to the Myo object. - ThalmicMyo thalmicMyo = myo.GetComponent (); - - if (!hub.hubInitialized) { - GUI.Label(new Rect (12, 8, Screen.width, Screen.height), - "Cannot contact Myo Connect. Is Myo Connect running?\n" + - "Press Q to try again." - ); - } else if (!thalmicMyo.isPaired) { - GUI.Label(new Rect (12, 8, Screen.width, Screen.height), - "No Myo currently paired." - ); - } else if (!thalmicMyo.armSynced) { - GUI.Label(new Rect (12, 8, Screen.width, Screen.height), - "Perform the Sync Gesture." - ); - } else { - GUI.Label (new Rect (12, 8, Screen.width, Screen.height), - "Fist: Vibrate Myo armband\n" + - "Wave in: Set box material to blue\n" + - "Wave out: Set box material to green\n" + - "Double tap: Reset box material\n" + - "Fingers spread: Set forward direction" - ); - } + if (Application.platform == RuntimePlatform.IPhonePlayer) { + if (GUILayout.Button ("Show Myo Connection Screen")) { + MyoIOSManager.ShowSettings (); + } + } + GUILayout.BeginHorizontal(); + + string numConnectionsString = GUILayout.TextField(""+numConnectionsAllowed); + if (!int.TryParse(numConnectionsString, out numConnectionsAllowed)) + { + numConnectionsAllowed = 1; + } + if (numConnectionsAllowed < 0) + { + numConnectionsAllowed = 1; + } + + if (GUILayout.Button("Set # of Connections Allowed")) + { + MyoIOSManager.ConnectionAllowance = numConnectionsAllowed; + } + + GUILayout.EndHorizontal(); + + if (GUILayout.Button("Enable EMG Streaming")) + { + thalmicMyo.SetEmgState(Thalmic.Myo.EmgState.Enabled); + //MyoIOSManager + } + + bool initialized = false; + + if (Application.platform == RuntimePlatform.IPhonePlayer) { + + initialized = true; + + } else { + initialized = ThalmicHub.instance.hubInitialized; + + if (!initialized) + { + GUILayout.Label ( + "Cannot contact Myo Connect. Is Myo Connect running?\n" + + "Press Q to try again." + ); + } + } + if (initialized) + { + if (!thalmicMyo.isPaired) { + GUILayout.Label ( + "No Myo currently paired." + ); + } else + { + if (!thalmicMyo.armSynced) { + GUILayout.Label ( + "Perform the Sync Gesture." + ); + } else { + //Show the myo pose commands if the myo has been synced + GUILayout.Label ( + "Fist: Vibrate Myo armband\n" + + "Wave in: Set box material to blue\n" + + "Wave out: Set box material to green\n" + + "Double tap: Reset box material\n" + + "Fingers spread: Set forward direction" + ); + } + + GUILayout.Label("Accelerometer"); + GUI.skin.label.fontSize = smallFontSize; + GUILayout.Label(string.Format("x: {0}, y: {1}, z: {2}", thalmicMyo.accelerometer.x, thalmicMyo.accelerometer.y, thalmicMyo.accelerometer.z)); + GUI.skin.label.fontSize = fontSize; + GUILayout.Label("Gyroscope"); + GUI.skin.label.fontSize = smallFontSize; + GUILayout.Label(string.Format("x: {0}, y: {1}, z: {2}", thalmicMyo.gyroscope.x, thalmicMyo.gyroscope.y, thalmicMyo.gyroscope.z)); + GUI.skin.label.fontSize = fontSize; + + //GUILayout.Label("Emg"); + + //GUILayout.Label(string.Format("x: {0}, y: {1}, z: {2}", thalmicMyo.gyroscope.x, thalmicMyo.gyroscope.y, thalmicMyo.gyroscope.z)); + + + } + + + + } + GUILayout.EndArea(); } + MyoIOSManager iosManager = null; + void Update () { ThalmicHub hub = ThalmicHub.instance; @@ -50,5 +126,7 @@ void Update () if (Input.GetKeyDown ("q")) { hub.ResetHub(); } + + } } diff --git a/project/Assets/Myo/Editor.meta b/project/Assets/Myo/Editor.meta new file mode 100644 index 0000000..e3ee5cf --- /dev/null +++ b/project/Assets/Myo/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e00cf0b459fa34201953c9cccf530ec3 +folderAsset: yes +timeCreated: 1435757496 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/Myo.NET.meta b/project/Assets/Myo/Scripts/Myo.NET.meta new file mode 100644 index 0000000..87f877d --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 62e15d1d1a87203418081dd579406dc5 +folderAsset: yes +timeCreated: 1435757729 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/Myo.NET/EventTypes.cs b/project/Assets/Myo/Scripts/Myo.NET/EventTypes.cs new file mode 100755 index 0000000..32db5e7 --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/EventTypes.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Thalmic.Myo +{ + public class MyoEventArgs : EventArgs + { + public MyoEventArgs(Myo myo, DateTime timestamp) + { + this.Myo = myo; + this.Timestamp = timestamp; + } + + public Myo Myo { get; private set; } + + public DateTime Timestamp { get; private set; } + } + + public class ArmSyncedEventArgs : MyoEventArgs + { + public ArmSyncedEventArgs(Myo myo, DateTime timestamp, Arm arm, XDirection xDirection) + : base(myo, timestamp) + { + this.Arm = arm; + this.XDirection = xDirection; + } + + public Arm Arm { get; private set; } + public XDirection XDirection { get; private set; } + } + + public class AccelerometerDataEventArgs : MyoEventArgs + { + public AccelerometerDataEventArgs(Myo myo, DateTime timestamp, Vector3 accelerometer) + : base(myo, timestamp) + { + this.Accelerometer = accelerometer; + } + + public Vector3 Accelerometer { get; private set; } + } + + public class GyroscopeDataEventArgs : MyoEventArgs + { + public GyroscopeDataEventArgs(Myo myo, DateTime timestamp, Vector3 gyroscope) + : base(myo, timestamp) + { + this.Gyroscope = gyroscope; + } + + public Vector3 Gyroscope { get; private set; } + } + + public class OrientationDataEventArgs : MyoEventArgs + { + public OrientationDataEventArgs(Myo myo, DateTime timestamp, Quaternion orientation) + : base(myo, timestamp) + { + this.Orientation = orientation; + } + + public Quaternion Orientation { get; private set; } + } + + public class PoseEventArgs : MyoEventArgs + { + public PoseEventArgs(Myo myo, DateTime timestamp, Pose pose) + : base(myo, timestamp) + { + this.Pose = pose; + } + + public Pose Pose { get; private set; } + } + + public class RssiEventArgs : MyoEventArgs + { + public RssiEventArgs(Myo myo, DateTime timestamp, sbyte rssi) + : base(myo, timestamp) + { + this.Rssi = rssi; + } + + public sbyte Rssi { get; private set; } + } + + public class EmgEventArgs: MyoEventArgs + { + public EmgEventArgs (Myo myo, DateTime timestamp, Dictionary emg) + : base (myo, timestamp) + { + this.Emg = emg; + } + + public Dictionary Emg { get; private set; } + } + +} diff --git a/project/Assets/Myo/Scripts/Myo.NET/EventTypes.cs.meta b/project/Assets/Myo/Scripts/Myo.NET/EventTypes.cs.meta new file mode 100644 index 0000000..41d9f43 --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/EventTypes.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: d735d9420fb48e4469664508947adb6a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/Myo.NET/Hub.cs b/project/Assets/Myo/Scripts/Myo.NET/Hub.cs new file mode 100755 index 0000000..9a35f05 --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Hub.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace Thalmic.Myo +{ + +#if UNITY_EDITOR || !UNITY_IOS + public class Hub : IDisposable + { + private static readonly DateTime TIMESTAMP_EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, 0); + + private bool _disposed = false; + private IntPtr _handle; + + private Thread _eventThread; + private bool _eventThreadShutdown = false; + + private Dictionary _myos = new Dictionary(); + + public Hub(string applicationIdentifier, EventHandler OnPaired) + { + if (OnPaired != null) { + Paired += OnPaired; + } + + if (libmyo.init_hub(out _handle, applicationIdentifier, IntPtr.Zero) != libmyo.Result.Success) + { + throw new InvalidOperationException("Unable to initialize Hub."); + } + + // spawn the event thread + StartEventThread(); + } + + // Deterministic destructor + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + StopEventThread(); + + if (disposing) + { + // free IDisposable managed objects (none right now) + } + + // free unmanaged objects + libmyo.shutdown_hub(_handle, IntPtr.Zero); + + _disposed = true; + } + } + + // Finalizer (non-deterministic) + ~Hub() + { + Dispose(false); + } + + public void SetLockingPolicy(LockingPolicy lockingPolicy) + { + libmyo.set_locking_policy(_handle, (libmyo.LockingPolicy)lockingPolicy, IntPtr.Zero); + } + + public event EventHandler Paired; + + internal void StartEventThread() + { + _eventThreadShutdown = false; + _eventThread = new Thread(new ThreadStart(EventThreadFn)); + _eventThread.Start(); + } + + internal void StopEventThread() + { + _eventThreadShutdown = true; + if (_eventThread != null) + { + _eventThread.Join(); + } + } + + private void EventThreadFn() + { + while (!_eventThreadShutdown) + { + GCHandle gch = GCHandle.Alloc(this); + + libmyo.run(_handle, 1000, (libmyo.Handler)HandleEvent, (IntPtr)gch, IntPtr.Zero); + } + } + + private static libmyo.HandlerResult HandleEvent(IntPtr userData, IntPtr evt) + { + GCHandle handle = (GCHandle)userData; + Hub self = (Hub)handle.Target; + + var type = libmyo.event_get_type(evt); + var timestamp = TIMESTAMP_EPOCH.AddMilliseconds(libmyo.event_get_timestamp(evt) / 1000); + var myoHandle = libmyo.event_get_myo(evt); + + switch (type) + { + case libmyo.EventType.Paired: + var myo = new Myo(self, myoHandle); + self._myos.Add(myoHandle, myo); + if (self.Paired != null) + { + self.Paired(self, new MyoEventArgs(myo, DateTime.Now)); + } + break; + + default: + Debug.Assert(self._myos[myoHandle] != null); + self._myos[myoHandle].HandleEvent(type, timestamp, evt); + break; + } + + return libmyo.HandlerResult.Continue; + } + } +#else + public class Hub + { + + } +#endif + + public enum LockingPolicy + { + None, + Standard + } +} diff --git a/project/Assets/Myo/Scripts/Myo.NET/Hub.cs.meta b/project/Assets/Myo/Scripts/Myo.NET/Hub.cs.meta new file mode 100644 index 0000000..4a310c1 --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Hub.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 39ce4176f4fdbf74b9e9dc75b6eb16bb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/Myo.NET/Myo.cs b/project/Assets/Myo/Scripts/Myo.NET/Myo.cs new file mode 100755 index 0000000..d6387be --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Myo.cs @@ -0,0 +1,236 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace Thalmic.Myo +{ + public class Myo + { + private readonly Hub _hub; + private IntPtr _handle; + + internal Myo(Hub hub, IntPtr handle) + { + Debug.Assert(handle != IntPtr.Zero, "Cannot construct Myo instance with null pointer."); + + _hub = hub; + _handle = handle; + } + + public event EventHandler Connected; + + public event EventHandler Disconnected; + + public event EventHandler ArmSynced; + + public event EventHandler ArmUnsynced; + + public event EventHandler PoseChange; + + public event EventHandler OrientationData; + + public event EventHandler AccelerometerData; + + public event EventHandler GyroscopeData; + + public event EventHandler Rssi; + + public event EventHandler Unlocked; + + public event EventHandler Locked; + + public event EventHandler Emg; + + internal Hub Hub + { + get { return _hub; } + } + + internal IntPtr Handle + { + get { return _handle; } + } + + +#if UNITY_EDITOR || !UNITY_IOS + + + public void SetEmgState(EmgState emgState) + { + libmyo.set_stream_eng (_handle, (libmyo.EmgState)emgState, IntPtr.Zero); + } + + public void Vibrate(VibrationType type) + { + libmyo.vibrate(_handle, (libmyo.VibrationType)type, IntPtr.Zero); + } + + public void RequestRssi() + { + libmyo.request_rssi(_handle, IntPtr.Zero); + } + + public void Unlock(UnlockType type) + { + libmyo.myo_unlock(_handle, (libmyo.UnlockType)type, IntPtr.Zero); + } + + public void Lock() + { + libmyo.myo_lock(_handle, IntPtr.Zero); + } + + public void NotifyUserAction() + { + libmyo.myo_notify_user_action(_handle, libmyo.UserActionType.Single, IntPtr.Zero); + } + + internal void HandleEvent(libmyo.EventType type, DateTime timestamp, IntPtr evt) + { + switch (type) + { + case libmyo.EventType.Connected: + if (Connected != null) + { + Connected(this, new MyoEventArgs(this, timestamp)); + } + break; + + case libmyo.EventType.Disconnected: + if (Disconnected != null) + { + Disconnected(this, new MyoEventArgs(this, timestamp)); + } + break; + + case libmyo.EventType.ArmSynced: + if (ArmSynced != null) + { + Arm arm = (Arm)libmyo.event_get_arm(evt); + XDirection xDirection = (XDirection)libmyo.event_get_x_direction(evt); + + ArmSynced(this, new ArmSyncedEventArgs(this, timestamp, arm, xDirection)); + } + break; + + case libmyo.EventType.ArmUnsynced: + if (ArmUnsynced != null) + { + ArmUnsynced(this, new MyoEventArgs(this, timestamp)); + } + break; + + case libmyo.EventType.Orientation: + if (AccelerometerData != null) + { + float x = libmyo.event_get_accelerometer(evt, 0); + float y = libmyo.event_get_accelerometer(evt, 1); + float z = libmyo.event_get_accelerometer(evt, 2); + + var accelerometer = new Vector3(x, y, z); + AccelerometerData(this, new AccelerometerDataEventArgs(this, timestamp, accelerometer)); + } + if (GyroscopeData != null) + { + float x = libmyo.event_get_gyroscope(evt, 0); + float y = libmyo.event_get_gyroscope(evt, 1); + float z = libmyo.event_get_gyroscope(evt, 2); + + var gyroscope = new Vector3(x, y, z); + GyroscopeData(this, new GyroscopeDataEventArgs(this, timestamp, gyroscope)); + } + if (OrientationData != null) + { + float x = libmyo.event_get_orientation(evt, libmyo.OrientationIndex.X); + float y = libmyo.event_get_orientation(evt, libmyo.OrientationIndex.Y); + float z = libmyo.event_get_orientation(evt, libmyo.OrientationIndex.Z); + float w = libmyo.event_get_orientation(evt, libmyo.OrientationIndex.W); + + var orientation = new Quaternion(x, y, z, w); + OrientationData(this, new OrientationDataEventArgs(this, timestamp, orientation)); + } + break; + + case libmyo.EventType.Pose: + if (PoseChange != null) + { + var pose = (Pose)libmyo.event_get_pose(evt); + PoseChange(this, new PoseEventArgs(this, timestamp, pose)); + } + break; + + case libmyo.EventType.Rssi: + if (Rssi != null) + { + var rssi = libmyo.event_get_rssi(evt); + Rssi(this, new RssiEventArgs(this, timestamp, rssi)); + } + break; + case libmyo.EventType.Unlocked: + if (Unlocked != null) + { + Unlocked(this, new MyoEventArgs(this, timestamp)); + } + break; + case libmyo.EventType.Locked: + if (Locked != null) + { + Locked(this, new MyoEventArgs(this, timestamp)); + } + break; + + case libmyo.EventType.Emg: + + Dictionary emgData = new Dictionary(); + for(int i = 0; i < 8;i++) + { + emgData[i] = libmyo.event_get_emg(evt, (uint)i); + } + + if (Emg != null) + { + Emg(this, new EmgEventArgs(this, timestamp, emgData)); + } + + + break; + } + } +#endif + } + + public enum Arm + { + Right, + Left, + Unknown + } + + public enum XDirection + { + TowardWrist, + TowardElbow, + Unknown + } + + public enum VibrationType + { + Short, + Medium, + Long + } + + public enum EmgState + { + Disabled, + Enabled + } + + public enum UnlockType + { + Timed = 0, ///< Unlock for a fixed period of time. + Hold = 1 ///< Unlock until explicitly told to re-lock. + } +} diff --git a/project/Assets/Myo/Scripts/Myo.NET/Myo.cs.meta b/project/Assets/Myo/Scripts/Myo.NET/Myo.cs.meta new file mode 100644 index 0000000..1630997 --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Myo.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f4b84caebd3c09a4fa9012ab17876d14 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/Myo.NET/Pose.cs b/project/Assets/Myo/Scripts/Myo.NET/Pose.cs new file mode 100755 index 0000000..b21504f --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Pose.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Thalmic.Myo +{ + public enum Pose + { + Rest = libmyo.PoseType.Rest, + Fist = libmyo.PoseType.Fist, + WaveIn = libmyo.PoseType.WaveIn, + WaveOut = libmyo.PoseType.WaveOut, + FingersSpread = libmyo.PoseType.FingersSpread, + DoubleTap = libmyo.PoseType.DoubleTap, + Unknown = libmyo.PoseType.Unknown + } +} diff --git a/project/Assets/Myo/Scripts/Myo.NET/Pose.cs.meta b/project/Assets/Myo/Scripts/Myo.NET/Pose.cs.meta new file mode 100644 index 0000000..bc2cc2c --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Pose.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 65993e3a88a07f0449a4500e77ec59f1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/Myo.NET/Properties.meta b/project/Assets/Myo/Scripts/Myo.NET/Properties.meta new file mode 100644 index 0000000..c7c5803 --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Properties.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 32dc09021faea9245b0d83143cfb3b3f +folderAsset: yes +timeCreated: 1435757729 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/Myo.NET/Properties/AssemblyInfo.cs b/project/Assets/Myo/Scripts/Myo.NET/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..6e15753 --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("myo-dotnet")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("myo-dotnet")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("656cd125-7846-4dae-acbe-08987a58a3c1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/project/Assets/Myo/Scripts/Myo.NET/Properties/AssemblyInfo.cs.meta b/project/Assets/Myo/Scripts/Myo.NET/Properties/AssemblyInfo.cs.meta new file mode 100644 index 0000000..43431fb --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Properties/AssemblyInfo.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 86ca2ea828b65bd47b5b200be4ca2dfc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/Myo.NET/Quaternion.cs b/project/Assets/Myo/Scripts/Myo.NET/Quaternion.cs new file mode 100755 index 0000000..a2d6551 --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Quaternion.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Thalmic.Myo +{ + public class Quaternion + { + private readonly float _x; + private readonly float _y; + private readonly float _z; + private readonly float _w; + + public Quaternion() + : this(0, 0, 0, 1) + { } + + public Quaternion(float x, float y, float z, float w) + { + _x = x; + _y = y; + _z = z; + _w = w; + } + + public float X { get { return _x; } } + + public float Y { get { return _y; } } + + public float Z { get { return _z; } } + + public float W { get { return _w; } } + + + + public static Quaternion operator -(Quaternion quat) + { + return new Quaternion(-quat._x, -quat._y, -quat._z, -quat._w); + } + + public static Quaternion operator +(Quaternion quat1, Quaternion quat2) + { + return new Quaternion(quat1._x + quat2._x, + quat1._y + quat2._y, + quat1._z + quat2._z, + quat1._w + quat2._w); + } + + public static Quaternion operator -(Quaternion quat1, Quaternion quat2) + { + return quat1 + (-quat2); + } + + public static Quaternion operator *(Quaternion quat, float scalar) + { + return new Quaternion(quat._x * scalar, + quat._y * scalar, + quat._z * scalar, + quat._w * scalar); + } + + public static Quaternion operator *(float scalar, Quaternion quat) + { + return quat * scalar; + } + + public static Quaternion operator /(Quaternion quat, float scalar) + { + return new Quaternion(quat._x / scalar, + quat._y / scalar, + quat._z / scalar, + quat._w / scalar); + } + + public static Quaternion operator *(Quaternion quat1, Quaternion quat2) + { + return new Quaternion(quat1._w * quat2._x + quat1._x * quat2._w + quat1._y * quat2._z - quat1._z * quat2._y, + quat1._w * quat2._y - quat1._x * quat2._z + quat1._y * quat2._w + quat1._z * quat2._x, + quat1._w * quat2._z + quat1._x * quat2._y - quat1._y * quat2._x + quat1._z * quat2._w, + quat1._w * quat2._w - quat1._x * quat2._x - quat1._y * quat2._y - quat1._z * quat2._z); + } + + public static Vector3 operator *(Quaternion quat, Vector3 vec) + { + var qvec = new Quaternion(vec.X, vec.Y, vec.Z, 0); + var result = quat * qvec * quat.Conjugate(); + return new Vector3(result.X, result.Y, result.Z); + } + + // + // TODO compound arithmetic operators + // + + public static Quaternion Normalize(Quaternion quat) + { + return (quat / quat.Magnitude()); + } + + /// Return the conjugate of the given Quaternion. + public Quaternion Conjugate() + { + return new Quaternion(-_x, -_y, -_z, _w); + } + + /// Calculate the roll angle represented by the given unit Quaternion. + public static float Roll(Quaternion quat) + { + return (float)Math.Atan2(2.0f * (quat._w * quat._x + quat._y * quat._z), + 1.0f - 2.0f * (quat._x * quat._x + quat._y * quat._y)); + } + + /// Calculate the pitch angle represented by the given unit Quaternion. + public static float Pitch(Quaternion quat) + { + return (float)Math.Asin(2.0f * (quat._w * quat._y - quat._z * quat._x)); + } + + /// Calculate the yaw angle represented by the given unit Quaternion. + public static float Yaw(Quaternion quat) + { + return (float)Math.Atan2(2.0f * (quat._w * quat._z + quat._x * quat._y), + 1.0f - 2.0f * (quat._y * quat._y + quat._z * quat._z)); + } + + public float Magnitude() + { + return (float)Math.Sqrt(_w * _w + _x * _x + _y * _y + _z * _z); + } + + public override string ToString() + { + return String.Format("{0},{1},{2},{3}", X, Y, Z, W); + } + } +} diff --git a/project/Assets/Myo/Scripts/Myo.NET/Quaternion.cs.meta b/project/Assets/Myo/Scripts/Myo.NET/Quaternion.cs.meta new file mode 100644 index 0000000..6eaa25d --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Quaternion.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 7b7c5306b60c4094495c65cc88350132 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/Myo.NET/Vector3.cs b/project/Assets/Myo/Scripts/Myo.NET/Vector3.cs new file mode 100755 index 0000000..021822a --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Vector3.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace Thalmic.Myo +{ + public class Vector3 + { + private readonly float[] _data; + + public Vector3() + : this(0, 0, 0) + { } + + public Vector3(float x, float y, float z) + { + _data = new float[3]; + _data[0] = x; + _data[1] = y; + _data[2] = z; + } + + public float X { get { return _data[0]; } } + + public float Y { get { return _data[1]; } } + + public float Z { get { return _data[2]; } } + + public float this[uint index] + { + get { return _data[index]; } + } + + public static Vector3 operator -(Vector3 vector) + { + return new Vector3(-vector.X, -vector.Y, -vector.Z); + } + + public static Vector3 operator +(Vector3 vector1, Vector3 vector2) + { + return new Vector3(vector1.X + vector2.X, + vector1.Y + vector2.Y, + vector1.Z + vector2.Z); + } + + public static Vector3 operator -(Vector3 vector1, Vector3 vector2) + { + return vector1 + (-vector2); + } + + public static Vector3 operator *(Vector3 vector, float scalar) + { + return new Vector3(vector.X * scalar, + vector.Y * scalar, + vector.Z * scalar); + } + + public static Vector3 operator *(float scalar, Vector3 vector) + { + return vector * scalar; + } + + public static Vector3 operator /(Vector3 vector, float scalar) + { + return new Vector3(vector.X / scalar, + vector.Y / scalar, + vector.Z / scalar); + } + + // + // TODO compound arithmetic operators + // + + public float Magnitude() + { + return (float)Math.Sqrt(X * X + Y * Y + Z * Z); + } + + // + // TODO dot product, cross product, etc. + // + + public override string ToString() + { + return String.Format("{0,6:0.00},{1,6:0.00},{2,6:0.00}", X, Y, Z); + } + } +} diff --git a/project/Assets/Myo/Scripts/Myo.NET/Vector3.cs.meta b/project/Assets/Myo/Scripts/Myo.NET/Vector3.cs.meta new file mode 100644 index 0000000..1496116 --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/Vector3.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: de1def232c6f8e04ca9a98384a579451 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/Myo.NET/libmyo.cs b/project/Assets/Myo/Scripts/Myo.NET/libmyo.cs new file mode 100755 index 0000000..c4c1831 --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/libmyo.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace Thalmic.Myo +{ + internal static class libmyo + { +#if UNITY_STANDALONE || UNITY_EDITOR + private const string MYO_DLL = "myo"; +#elif UNITY_ANDROID + private const string MYO_DLL = "myo-android"; +#elif WIN64 + private const string MYO_DLL = "myo64.dll"; +#elif WIN32 + private const string MYO_DLL = "myo32.dll"; +#endif + + public enum EventType + { + Paired, + Unpaired, + Connected, + Disconnected, + ArmSynced, + ArmUnsynced, + Orientation, + Pose, + Rssi, + Unlocked, + Locked, + Emg, + BatteryLevel, + WarmupCompleted + } + + public enum Result + { + Success, + Error, + ErrorInvalidArgument, + ErrorRuntime + } + + public enum VibrationType + { + Short, + Medium, + Long + } + + public enum PoseType + { + Rest = 0, + Fist = 1, + WaveIn = 2, + WaveOut = 3, + FingersSpread = 4, + DoubleTap = 5, + Unknown = 0xffff + } + + public enum UnlockType + { + Timed = 0, + Hold = 1 + } + + public enum UserActionType + { + Single = 0 + } + + public enum LockingPolicy + { + None, + Standard + } + + public enum EmgState + { + Disabled, + Enabled + } + +#if !UNITY_IPHONE || UNITY_EDITOR + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_emg", + CallingConvention = CallingConvention.Cdecl)] + public static extern sbyte event_get_emg(IntPtr evt, uint sensor); + + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_set_stream_emg", + CallingConvention = CallingConvention.Cdecl)] + public static extern Result set_stream_eng(IntPtr myo, EmgState emg, IntPtr out_error); + + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_error_cstring", + CallingConvention = CallingConvention.Cdecl)] + public static extern string error_cstring(IntPtr error); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_error_kind", + CallingConvention = CallingConvention.Cdecl)] + public static extern Result error_kind(IntPtr error); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_free_error_details", + CallingConvention = CallingConvention.Cdecl)] + public static extern void free_error_details(IntPtr error); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_init_hub", + CallingConvention = CallingConvention.Cdecl)] + public static extern Result init_hub(out IntPtr hub, string applicationIdentifier, IntPtr error); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_shutdown_hub", + CallingConvention = CallingConvention.Cdecl)] + public static extern Result shutdown_hub(IntPtr hub, IntPtr error); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_set_locking_policy", + CallingConvention = CallingConvention.Cdecl)] + public static extern Result set_locking_policy(IntPtr hub, LockingPolicy lockingPolicy, IntPtr error); + + + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_vibrate", + CallingConvention = CallingConvention.Cdecl)] + public static extern void vibrate(IntPtr myo, VibrationType type, IntPtr error); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_request_rssi", + CallingConvention = CallingConvention.Cdecl)] + public static extern void request_rssi(IntPtr myo, IntPtr error); + + + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_myo_unlock", + CallingConvention = CallingConvention.Cdecl)] + public static extern void myo_unlock(IntPtr myo, UnlockType unlockType, IntPtr error); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_myo_lock", + CallingConvention = CallingConvention.Cdecl)] + public static extern void myo_lock(IntPtr myo, IntPtr error); + + + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_myo_notify_user_action", + CallingConvention = CallingConvention.Cdecl)] + public static extern void myo_notify_user_action(IntPtr myo, UserActionType type, IntPtr error); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_type", + CallingConvention = CallingConvention.Cdecl)] + public static extern EventType event_get_type(IntPtr evt); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_timestamp", + CallingConvention = CallingConvention.Cdecl)] + public static extern UInt64 event_get_timestamp(IntPtr evt); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_myo", + CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr event_get_myo(IntPtr evt); + + public enum VersionComponent + { + Major, + Minor, + Patch + } + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_firmware_version", + CallingConvention = CallingConvention.Cdecl)] + public static extern uint event_get_firmware_version(IntPtr evt, VersionComponent component); + + public enum Arm { + Right, + Left, + Unknown + } + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_arm", + CallingConvention = CallingConvention.Cdecl)] + public static extern Arm event_get_arm(IntPtr evt); + + public enum XDirection { + TowardWrist, + TowardElbow, + Unknown + } + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_x_direction", + CallingConvention = CallingConvention.Cdecl)] + public static extern XDirection event_get_x_direction(IntPtr evt); + + public enum OrientationIndex + { + X = 0, + Y = 1, + Z = 2, + W = 3 + } + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_orientation", + CallingConvention = CallingConvention.Cdecl)] + public static extern float event_get_orientation(IntPtr evt, OrientationIndex index); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_accelerometer", + CallingConvention = CallingConvention.Cdecl)] + public static extern float event_get_accelerometer(IntPtr evt, uint index); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_gyroscope", + CallingConvention = CallingConvention.Cdecl)] + public static extern float event_get_gyroscope(IntPtr evt, uint index); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_pose", + CallingConvention = CallingConvention.Cdecl)] + public static extern PoseType event_get_pose(IntPtr evt); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_event_get_rssi", + CallingConvention = CallingConvention.Cdecl)] + public static extern sbyte event_get_rssi(IntPtr evt); + + public enum HandlerResult + { + Continue, + Stop + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate HandlerResult Handler(IntPtr userData, IntPtr evt); + + [DllImport(MYO_DLL, + EntryPoint = "libmyo_run", + CallingConvention = CallingConvention.Cdecl)] + public static extern Result run(IntPtr hub, uint durationMs, Handler handler, IntPtr userData, IntPtr error); + #endif + } + +} diff --git a/project/Assets/Myo/Scripts/Myo.NET/libmyo.cs.meta b/project/Assets/Myo/Scripts/Myo.NET/libmyo.cs.meta new file mode 100644 index 0000000..9bb858c --- /dev/null +++ b/project/Assets/Myo/Scripts/Myo.NET/libmyo.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 360ef1f02bfc1e5429ff6fae9b791360 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/MyoBindings.cs b/project/Assets/Myo/Scripts/MyoBindings.cs new file mode 100644 index 0000000..415ca6e --- /dev/null +++ b/project/Assets/Myo/Scripts/MyoBindings.cs @@ -0,0 +1,86 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System; +using System.Runtime.InteropServices; + +namespace Thalmic +{ + using MiniJSON; + + public class MyoIOSDevice + { + public bool isConnected; + public string name; + public string identifier; + public string state; + public bool isLocked; + public string poseType; + public string poseTimestamp; + public string pose; + public Quaternion quaternion; + public int arm; + public int xdirection; + } + + public class MyoBindings { + + #if UNITY_IOS + [DllImport ("__Internal")] + public static extern void myo_SetApplicationID(string appID); + + [DllImport ("__Internal")] + public static extern bool myo_IsArmLocked(); + + [DllImport ("__Internal")] + public static extern void myo_ShowSettings(); + + [DllImport ("__Internal")] + public static extern string myo_GetMyos(); + + [DllImport ("__Internal")] + public static extern void myo_SetLockingPolicy(int policy); + + [DllImport ("__Internal")] + public static extern void myo_SetShouldSendUsageData(bool value); + + [DllImport ("__Internal")] + public static extern void myo_SetShouldNotifyInBackground(bool value); + + [DllImport ("__Internal")] + public static extern bool myo_VibrateWithLength(string myoId, int length); + + [DllImport ("__Internal")] + public static extern bool myo_SetStreamEmg(string myoId, int type); + + [DllImport ("__Internal")] + public static extern bool myo_IndicateUserAction(string myoId); + + [DllImport ("__Internal")] + public static extern bool myo_Lock(string myoId); + + [DllImport ("__Internal")] + public static extern bool myo_UnlockWithType(string myoId, int type); + + [DllImport ("__Internal")] + public static extern int myo_MyoConnectionAllowance(); + + [DllImport ("__Internal")] + public static extern void myo_SetMyoConnectionAllowance(int value); + + //This method deserializes the json retreived from the objective c bindings which will be used to update the thalmic myo objects in the unity scene + public static List GetMyos() + { + string myosJSON = myo_GetMyos (); + Debug.Log("got myos" + myosJSON); + if (myosJSON == null) + return null; + + //JSONNode result = JSON.Parse(myosJSON); + + List myos = new List(); + return myos; + } + #endif + } +} \ No newline at end of file diff --git a/project/Assets/Myo/Scripts/MyoBindings.cs.meta b/project/Assets/Myo/Scripts/MyoBindings.cs.meta new file mode 100644 index 0000000..ac06b5f --- /dev/null +++ b/project/Assets/Myo/Scripts/MyoBindings.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 46b2c08a03f2d488d8166d4160f33b86 +timeCreated: 1435758223 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/MyoIOSManager.cs b/project/Assets/Myo/Scripts/MyoIOSManager.cs new file mode 100644 index 0000000..84faa47 --- /dev/null +++ b/project/Assets/Myo/Scripts/MyoIOSManager.cs @@ -0,0 +1,296 @@ +using UnityEngine; +using System.Collections; + +using Thalmic; +using Pose = Thalmic.Myo.Pose; +using Thalmic.MiniJSON; + +/** + * + * This class is automatically generated on the iOS platform by the Thalmic Hub instance. + * The manager will use the Myo iOS bindings to access the native Myo iOS SDK + * + * */ +using System.Collections.Generic; + + +public class MyoIOSManager : MonoBehaviour { + + #if UNITY_IPHONE + + void Start() + { + Debug.Log("Starting iOS Manager"); + MyoBindings.myo_SetApplicationID(ThalmicHub.instance.applicationIdentifier); + MyoBindings.myo_SetLockingPolicy((int)ThalmicHub.instance.lockingPolicy); + } + + #region Myo iOS Methods + //IOS Specific methods + public static void ShowSettings() + { + Debug.Log("Showing iOS Connection Settings"); + + MyoBindings.myo_ShowSettings(); + } + + private static int _connectionAllowance = -1; + public static int ConnectionAllowance + { + get + { + return _connectionAllowance < 0 ? MyoBindings.myo_MyoConnectionAllowance() : _connectionAllowance; + } + set + { + if (value >= 0) + { + _connectionAllowance = value; + Debug.Log("Setting connection string allowance to be " + _connectionAllowance); + MyoBindings.myo_SetMyoConnectionAllowance(_connectionAllowance); + } + } + } + + #endregion + + #region Myo iOS Notifications + void didConnectDevice() + { + //todo...determine which myo id this is... + + //if (ThalmicHub.DidConnectDevice != null) + // ThalmicHub.DidConnectDevice (PrimaryMyo); + } + + void didDisconnectDevice() + { + //if (ThalmicHub.DidDisconnectDevice != null) + // ThalmicHub.DidDisconnectDevice (PrimaryMyo); + } + + void didReceiveEmgEvent(string eventData) + { + if (eventData == null || eventData.Length == 0) + return; + + var dict = Json.Deserialize (eventData) as Dictionary; + + string myoIdentifier = (string)dict["myoIdentifier"]; + + List rawDataGeneric = (List)dict ["rawData"]; + + ThalmicMyo targetMyo = GetMyo(myoIdentifier); + if (targetMyo != null) + { + for(int i = 0; i < rawDataGeneric.Count;i++){ + targetMyo.emg[i] = (sbyte)((long)( rawDataGeneric[i])); + } + } + } + + void didUnlockDevice(string eventData) + { + if (eventData == null || eventData.Length == 0) + return; + + var dict = Json.Deserialize(eventData) as Dictionary; + + string myoIdentifier = (string) dict["myoIdentifier"]; + ThalmicMyo targetMyo = GetMyo(myoIdentifier); + if (targetMyo != null) + { + if (ThalmicHub.DidUnlockDevice != null) + ThalmicHub.DidUnlockDevice (targetMyo); + targetMyo._myoUnlocked = true; + } + } + + void didLockDevice(string eventData) + { + if (eventData == null || eventData.Length == 0) + return; + + var dict = Json.Deserialize(eventData) as Dictionary; + + string myoIdentifier = (string)dict["myoIdentifier"]; + ThalmicMyo targetMyo = GetMyo(myoIdentifier); + + if (targetMyo != null) + { + if (ThalmicHub.DidUnlockDevice != null) + ThalmicHub.DidUnlockDevice (targetMyo); + targetMyo._myoUnlocked = false; + } + } + + void didSyncArmEvent(string eventData) + { + if (eventData == null || eventData.Length == 0) + return; + + var dict = Json.Deserialize(eventData) as Dictionary; + + string myoIdentifier = (string) dict["myoIdentifier"]; + ThalmicMyo targetMyo = GetMyo(myoIdentifier); + int armXDirection = (int)((long) dict["armXDirection"]); + + if (targetMyo != null) + { + if (ThalmicHub.DidSyncArm != null) + ThalmicHub.DidSyncArm (targetMyo); + + targetMyo._myoXDirection = (Thalmic.Myo.XDirection) armXDirection; + targetMyo._myoArmSynced = true; + } + } + + void didUnsyncArmEvent(string eventData) + { + if (eventData == null || eventData.Length == 0) + return; + + var dict = Json.Deserialize(eventData) as Dictionary; + string myoIdentifier = (string)dict["myoIdentifier"]; + ThalmicMyo targetMyo = GetMyo(myoIdentifier); + int armXDirection = (int)((long)(dict["armXDirection"])); + + if (targetMyo != null) + { + if (ThalmicHub.DidUnsyncArm != null) + ThalmicHub.DidUnsyncArm (targetMyo); + + targetMyo._myoArmSynced = false; + } + } + + + Thalmic.Myo.Vector3 jsonDictToVector3(Dictionary dict) + { + if (dict != null && dict["x"] is double && dict["y"] is double && dict["z"] is double) + { + return new Thalmic.Myo.Vector3((float)((double)dict["x"]), (float)((double) dict["y"]),(float)( (double)dict["z"])); + } + return new Thalmic.Myo.Vector3 (); + } + + Thalmic.Myo.Quaternion jsonDictToQuaternion(Dictionary dict) + { + return new Thalmic.Myo.Quaternion((float)((double)dict["x"]), (float)((double) dict["y"]),(float)( (double)dict["z"]),(float)( (double)dict["w"])); + } + + public void didReceiveGyroscopeEvent(string eventData) + { + if (eventData == null || eventData.Length == 0) + return; + + var dict = Json.Deserialize(eventData) as Dictionary; + + var vectorNode = dict["vector"] as Dictionary; + string myoIdentifier = (string)dict["myoIdentifier"]; + ThalmicMyo targetMyo = GetMyo(myoIdentifier); + + if (targetMyo != null) + { + targetMyo._myoGyroscope = jsonDictToVector3(vectorNode); + if (ThalmicHub.DidUpdateAccelerometerData != null) { + //ThalmicHub.DidUpdateAccelerometerData(targetMyo, acceleration); + } + } + } + + + + + void didReceiveOrientationEvent(string eventData) + { + + if (eventData == null || eventData.Length == 0) + return; + //deserialize the jsonified orientation event + var dict = Json.Deserialize(eventData) as Dictionary; + + string myoIdentifier = (string)dict["myoIdentifier"]; + ThalmicMyo targetMyo = GetMyo(myoIdentifier); + + var quaternionDict = dict["quaternion"] as Dictionary; + + if (targetMyo != null) + { + targetMyo._myoQuaternion = jsonDictToQuaternion(quaternionDict); + } + } + + void didReceiveAccelerometerEvent(string eventData) + { + if (eventData == null || eventData.Length == 0) + return; + + var dict = Json.Deserialize(eventData) as Dictionary; + var vectorNode = dict["acceleration"] as Dictionary; + string myoIdentifier = (string)dict["myoIdentifier"]; + ThalmicMyo targetMyo = GetMyo(myoIdentifier); + + if (targetMyo != null) + { + targetMyo._myoAccelerometer = jsonDictToVector3(vectorNode); + if (ThalmicHub.DidUpdateAccelerometerData != null) { + + } + } + } + + void didReceivePoseChange(string param) + { + Pose receivedPose = Pose.Unknown; + + for (int i = (int) Pose.Rest; i <= (int) Pose.Unknown; i++) { + Pose currPose = (Pose) i; + if (currPose.ToString().Equals(param)) + { + receivedPose = currPose; + break; + } + } + //Update all myos for now because we don't have the myo id + foreach(ThalmicMyo myo in ThalmicHub.instance._myos) + { + if (ThalmicHub.DidReceivePoseChange != null) { + ThalmicHub.DidReceivePoseChange(null, receivedPose); + } + myo._myoPose = receivedPose; + } + } + #endregion + + #region Helper Methods + ThalmicMyo GetMyo(string myoId) + { + if ( ThalmicHub.instance == null || ThalmicHub.instance._myos == null) return null; + + if (myoId == null || myoId.Length <= 0) return null; + + foreach(ThalmicMyo myo in ThalmicHub.instance._myos) + { + if (myo.identifier.Equals(myoId)) + { + return myo; + } + } + + foreach(ThalmicMyo myo in ThalmicHub.instance._myos) + { + if (myo.identifier == null || myo.identifier.Length == 0) + { + myo.identifier = myoId; + return myo; + } + } + + return null;; + } + #endregion + + #endif + +} \ No newline at end of file diff --git a/project/Assets/Myo/Scripts/MyoIOSManager.cs.meta b/project/Assets/Myo/Scripts/MyoIOSManager.cs.meta new file mode 100644 index 0000000..2a28fd4 --- /dev/null +++ b/project/Assets/Myo/Scripts/MyoIOSManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: cfc55436137524a09a9d6029b60d79b4 +timeCreated: 1435758225 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Scripts/ThalmicHub.cs b/project/Assets/Myo/Scripts/ThalmicHub.cs old mode 100644 new mode 100755 index 96262b9..7e48652 --- a/project/Assets/Myo/Scripts/ThalmicHub.cs +++ b/project/Assets/Myo/Scripts/ThalmicHub.cs @@ -3,6 +3,7 @@ #if UNITY_EDITOR using UnityEditor; #endif +using System; using System.Collections.Generic; @@ -41,11 +42,15 @@ public bool hubInitialized { // after asking the user to ensure that Myo Connect is running). public bool ResetHub() { if (_hub != null) { + +#if UNITY_EDITOR || !UNITY_IPHONE + _hub.Dispose (); _hub = null; - +#endif foreach (ThalmicMyo myo in _myos) { myo.internalMyo = null; + myo.identifier = null; } } #if UNITY_ANDROID && !UNITY_EDITOR @@ -80,6 +85,14 @@ void Awake () // Do not destroy this game object. This will ensure that it remains active even when // switching scenes. DontDestroyOnLoad(this); + + //if we are running on iOS initialize the iOSManager to receive updates to myo objects + if (Application.platform == RuntimePlatform.IPhonePlayer) + { + GameObject go = new GameObject("MyoIOSManager"); + go.AddComponent(); + go.transform.parent = this.transform; + } for (int i = 0; i < transform.childCount; ++i) { Transform child = transform.GetChild (i); @@ -118,29 +131,30 @@ void Awake () } private bool createHub () { + + #if UNITY_EDITOR || !UNITY_IPHONE try { _hub = new Thalmic.Myo.Hub (applicationIdentifier, hub_MyoPaired); _hub.SetLockingPolicy (lockingPolicy); - } catch (System.Exception) { - Debug.Log ("ThalmicHub failed to initialize."); + } catch (System.Exception e) { + Debug.Log ("ThalmicHub failed to initialize." + e.ToString()); return false; } + #endif return true; } void OnApplicationQuit () { if (_hub != null) { +#if UNITY_EDITOR || !UNITY_IOS _hub.Dispose (); _hub = null; +#endif } } - void Update () - { - } - void hub_MyoPaired (object sender, Thalmic.Myo.MyoEventArgs e) { foreach (ThalmicMyo myo in _myos) { @@ -155,5 +169,17 @@ void hub_MyoPaired (object sender, Thalmic.Myo.MyoEventArgs e) private Thalmic.Myo.Hub _hub = null; - private List _myos = new List(); + public List _myos = new List(); + + //Events + public static Action DidUpdateAccelerometerData; + public static Action DidUpdateOrientationData; + public static Action DidReceivePoseChange; + public static Action DidReceiveEmgData; + public static Action DidConnectDevice; + public static Action DidDisconnectDevice; + public static Action DidUnlockDevice; + public static Action DidLockDevice; + public static Action DidSyncArm; + public static Action DidUnsyncArm; } diff --git a/project/Assets/Myo/Scripts/ThalmicMyo.cs b/project/Assets/Myo/Scripts/ThalmicMyo.cs old mode 100644 new mode 100755 index 3c87869..1a80855 --- a/project/Assets/Myo/Scripts/ThalmicMyo.cs +++ b/project/Assets/Myo/Scripts/ThalmicMyo.cs @@ -6,12 +6,17 @@ using VibrationType = Thalmic.Myo.VibrationType; using Pose = Thalmic.Myo.Pose; using UnlockType = Thalmic.Myo.UnlockType; - +using EmgState = Thalmic.Myo.EmgState; // Represents a Myo armband. Myo's orientation is made available through transform.localRotation, and other properties // like the current pose are provided explicitly below. All spatial data about Myo is provided following Unity // coordinate system conventions (the y axis is up, the z axis is forward, and the coordinate system is left-handed). +using System.Collections.Generic; + + public class ThalmicMyo : MonoBehaviour { + public string identifier; + // True if and only if Myo has detected that it is on an arm. public bool armSynced; @@ -38,33 +43,72 @@ public class ThalmicMyo : MonoBehaviour { // following Unity coordinate system conventions. public Vector3 gyroscope; + // Myo's current emg reading. Key represents the sensor index + public Dictionary emg; + // True if and only if this Myo armband has paired successfully, at which point it will provide data and a // connection with it will be maintained when possible. public bool isPaired { - get { return _myo != null; } + get { return _myo != null || (identifier !=null && identifier.Length > 0); } } // Vibrate the Myo with the provided type of vibration, e.g. VibrationType.Short or VibrationType.Medium. public void Vibrate (VibrationType type) { + +#if UNITY_EDITOR || !UNITY_IOS + _myo.Vibrate (type); +#else + Thalmic.MyoBindings.myo_VibrateWithLength(identifier, (int) type); +#endif } + public void SetEmgState(EmgState emgState) + { + +#if UNITY_EDITOR + _myo.SetEmgState (emgState); +#elif UNITY_IOS + Thalmic.MyoBindings.myo_SetStreamEmg(identifier, (int)emgState); +#endif + } + // Cause the Myo to unlock with the provided type of unlock. e.g. UnlockType.Timed or UnlockType.Hold. public void Unlock (UnlockType type) { - _myo.Unlock (type); + + #if UNITY_EDITOR || !UNITY_IOS + _myo.Unlock (type); + #else + Thalmic.MyoBindings.myo_UnlockWithType(identifier, (int) type); + #endif } // Cause the Myo to re-lock immediately. public void Lock () { - _myo.Lock (); + + #if UNITY_EDITOR || !UNITY_IOS + _myo.Lock (); + #else + Thalmic.MyoBindings.myo_Lock(identifier); + #endif } /// Notify the Myo that a user action was recognized. public void NotifyUserAction () { - _myo.NotifyUserAction (); + + #if UNITY_EDITOR || !UNITY_IOS + + _myo.NotifyUserAction (); + + #else + Thalmic.MyoBindings.myo_IndicateUserAction(identifier); + #endif } void Start() { + + identifier = ""; + } void Update() { @@ -133,10 +177,16 @@ void myo_OnUnlock(object sender, Thalmic.Myo.MyoEventArgs e) { } void myo_OnLock(object sender, Thalmic.Myo.MyoEventArgs e) { - lock (_lock) { - _myoUnlocked = false; - } - } + lock (_lock) { + _myoUnlocked = false; + } + } + + void myo_OnEmg(object sender, Thalmic.Myo.EmgEventArgs e){ + lock (_lock) { + emg = e.Emg; + } + } public Thalmic.Myo.Myo internalMyo { get { return _myo; } @@ -150,6 +200,7 @@ public Thalmic.Myo.Myo internalMyo { _myo.PoseChange -= myo_OnPoseChange; _myo.Unlocked -= myo_OnUnlock; _myo.Locked -= myo_OnLock; + _myo.Emg -= myo_OnEmg; } _myo = value; if (value != null) { @@ -161,20 +212,20 @@ public Thalmic.Myo.Myo internalMyo { value.PoseChange += myo_OnPoseChange; value.Unlocked += myo_OnUnlock; value.Locked += myo_OnLock; + value.Emg += myo_OnEmg; } } } private Object _lock = new Object(); - private bool _myoArmSynced = false; - private Arm _myoArm = Arm.Unknown; - private XDirection _myoXDirection = XDirection.Unknown; - private Thalmic.Myo.Quaternion _myoQuaternion = null; - private Thalmic.Myo.Vector3 _myoAccelerometer = null; - private Thalmic.Myo.Vector3 _myoGyroscope = null; - private Pose _myoPose = Pose.Unknown; - private bool _myoUnlocked = false; - + public bool _myoArmSynced = false; + public Arm _myoArm = Arm.Unknown; + public XDirection _myoXDirection = XDirection.Unknown; + public Thalmic.Myo.Quaternion _myoQuaternion = null; + public Thalmic.Myo.Vector3 _myoAccelerometer = null; + public Thalmic.Myo.Vector3 _myoGyroscope = null; + public Pose _myoPose = Pose.Unknown; + public bool _myoUnlocked = false; private Thalmic.Myo.Myo _myo; } diff --git a/project/Assets/Myo/Utils.meta b/project/Assets/Myo/Utils.meta new file mode 100644 index 0000000..3f76b4c --- /dev/null +++ b/project/Assets/Myo/Utils.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0ce68964c454747f78b7f9c7e32e066c +folderAsset: yes +timeCreated: 1435772602 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/Assets/Myo/Utils/MiniJSON.cs b/project/Assets/Myo/Utils/MiniJSON.cs new file mode 100644 index 0000000..bba68f2 --- /dev/null +++ b/project/Assets/Myo/Utils/MiniJSON.cs @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2013 Calvin Rien + * + * Based on the JSON parser by Patrick van Bergen + * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html + * + * Simplified it so that it doesn't throw exceptions + * and can be used in Unity iPhone with maximum code stripping. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + + +/* + * This version of simple JSON is included in the Thalmic Myo SDK. + * */ + + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Thalmic.MiniJSON { + // Example usage: + // + // using UnityEngine; + // using System.Collections; + // using System.Collections.Generic; + // using MiniJSON; + // + // public class MiniJSONTest : MonoBehaviour { + // void Start () { + // var jsonString = "{ \"array\": [1.44,2,3], " + + // "\"object\": {\"key1\":\"value1\", \"key2\":256}, " + + // "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " + + // "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " + + // "\"int\": 65536, " + + // "\"float\": 3.1415926, " + + // "\"bool\": true, " + + // "\"null\": null }"; + // + // var dict = Json.Deserialize(jsonString) as Dictionary; + // + // Debug.Log("deserialized: " + dict.GetType()); + // Debug.Log("dict['array'][0]: " + ((List) dict["array"])[0]); + // Debug.Log("dict['string']: " + (string) dict["string"]); + // Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles + // Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs + // Debug.Log("dict['unicode']: " + (string) dict["unicode"]); + // + // var str = Json.Serialize(dict); + // + // Debug.Log("serialized: " + str); + // } + // } + + /// + /// This class encodes and decodes JSON strings. + /// Spec. details, see http://www.json.org/ + /// + /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary. + /// All numbers are parsed to doubles. + /// + public static class Json { + /// + /// Parses the string json into a value + /// + /// A JSON string. + /// An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false + public static object Deserialize(string json) { + // save the string for debug information + if (json == null) { + return null; + } + + return Parser.Parse(json); + } + + sealed class Parser : IDisposable { + const string WORD_BREAK = "{}[],:\""; + + public static bool IsWordBreak(char c) { + return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1; + } + + enum TOKEN { + NONE, + CURLY_OPEN, + CURLY_CLOSE, + SQUARED_OPEN, + SQUARED_CLOSE, + COLON, + COMMA, + STRING, + NUMBER, + TRUE, + FALSE, + NULL + }; + + StringReader json; + + Parser(string jsonString) { + json = new StringReader(jsonString); + } + + public static object Parse(string jsonString) { + using (var instance = new Parser(jsonString)) { + return instance.ParseValue(); + } + } + + public void Dispose() { + json.Dispose(); + json = null; + } + + Dictionary ParseObject() { + Dictionary table = new Dictionary(); + + // ditch opening brace + json.Read(); + + // { + while (true) { + switch (NextToken) { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.CURLY_CLOSE: + return table; + default: + // name + string name = ParseString(); + if (name == null) { + return null; + } + + // : + if (NextToken != TOKEN.COLON) { + return null; + } + // ditch the colon + json.Read(); + + // value + table[name] = ParseValue(); + break; + } + } + } + + List ParseArray() { + List array = new List(); + + // ditch opening bracket + json.Read(); + + // [ + var parsing = true; + while (parsing) { + TOKEN nextToken = NextToken; + + switch (nextToken) { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.SQUARED_CLOSE: + parsing = false; + break; + default: + object value = ParseByToken(nextToken); + + array.Add(value); + break; + } + } + + return array; + } + + object ParseValue() { + TOKEN nextToken = NextToken; + return ParseByToken(nextToken); + } + + object ParseByToken(TOKEN token) { + switch (token) { + case TOKEN.STRING: + return ParseString(); + case TOKEN.NUMBER: + return ParseNumber(); + case TOKEN.CURLY_OPEN: + return ParseObject(); + case TOKEN.SQUARED_OPEN: + return ParseArray(); + case TOKEN.TRUE: + return true; + case TOKEN.FALSE: + return false; + case TOKEN.NULL: + return null; + default: + return null; + } + } + + string ParseString() { + StringBuilder s = new StringBuilder(); + char c; + + // ditch opening quote + json.Read(); + + bool parsing = true; + while (parsing) { + + if (json.Peek() == -1) { + parsing = false; + break; + } + + c = NextChar; + switch (c) { + case '"': + parsing = false; + break; + case '\\': + if (json.Peek() == -1) { + parsing = false; + break; + } + + c = NextChar; + switch (c) { + case '"': + case '\\': + case '/': + s.Append(c); + break; + case 'b': + s.Append('\b'); + break; + case 'f': + s.Append('\f'); + break; + case 'n': + s.Append('\n'); + break; + case 'r': + s.Append('\r'); + break; + case 't': + s.Append('\t'); + break; + case 'u': + var hex = new char[4]; + + for (int i=0; i< 4; i++) { + hex[i] = NextChar; + } + + s.Append((char) Convert.ToInt32(new string(hex), 16)); + break; + } + break; + default: + s.Append(c); + break; + } + } + + return s.ToString(); + } + + object ParseNumber() { + string number = NextWord; + + if (number.IndexOf('.') == -1) { + long parsedInt; + Int64.TryParse(number, out parsedInt); + return parsedInt; + } + + double parsedDouble; + Double.TryParse(number, out parsedDouble); + return parsedDouble; + } + + void EatWhitespace() { + while (Char.IsWhiteSpace(PeekChar)) { + json.Read(); + + if (json.Peek() == -1) { + break; + } + } + } + + char PeekChar { + get { + return Convert.ToChar(json.Peek()); + } + } + + char NextChar { + get { + return Convert.ToChar(json.Read()); + } + } + + string NextWord { + get { + StringBuilder word = new StringBuilder(); + + while (!IsWordBreak(PeekChar)) { + word.Append(NextChar); + + if (json.Peek() == -1) { + break; + } + } + + return word.ToString(); + } + } + + TOKEN NextToken { + get { + EatWhitespace(); + + if (json.Peek() == -1) { + return TOKEN.NONE; + } + + switch (PeekChar) { + case '{': + return TOKEN.CURLY_OPEN; + case '}': + json.Read(); + return TOKEN.CURLY_CLOSE; + case '[': + return TOKEN.SQUARED_OPEN; + case ']': + json.Read(); + return TOKEN.SQUARED_CLOSE; + case ',': + json.Read(); + return TOKEN.COMMA; + case '"': + return TOKEN.STRING; + case ':': + return TOKEN.COLON; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return TOKEN.NUMBER; + } + + switch (NextWord) { + case "false": + return TOKEN.FALSE; + case "true": + return TOKEN.TRUE; + case "null": + return TOKEN.NULL; + } + + return TOKEN.NONE; + } + } + } + + /// + /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string + /// + /// A Dictionary<string, object> / List<object> + /// A JSON encoded string, or null if object 'json' is not serializable + public static string Serialize(object obj) { + return Serializer.Serialize(obj); + } + + sealed class Serializer { + StringBuilder builder; + + Serializer() { + builder = new StringBuilder(); + } + + public static string Serialize(object obj) { + var instance = new Serializer(); + + instance.SerializeValue(obj); + + return instance.builder.ToString(); + } + + void SerializeValue(object value) { + IList asList; + IDictionary asDict; + string asStr; + + if (value == null) { + builder.Append("null"); + } else if ((asStr = value as string) != null) { + SerializeString(asStr); + } else if (value is bool) { + builder.Append((bool) value ? "true" : "false"); + } else if ((asList = value as IList) != null) { + SerializeArray(asList); + } else if ((asDict = value as IDictionary) != null) { + SerializeObject(asDict); + } else if (value is char) { + SerializeString(new string((char) value, 1)); + } else { + SerializeOther(value); + } + } + + void SerializeObject(IDictionary obj) { + bool first = true; + + builder.Append('{'); + + foreach (object e in obj.Keys) { + if (!first) { + builder.Append(','); + } + + SerializeString(e.ToString()); + builder.Append(':'); + + SerializeValue(obj[e]); + + first = false; + } + + builder.Append('}'); + } + + void SerializeArray(IList anArray) { + builder.Append('['); + + bool first = true; + + foreach (object obj in anArray) { + if (!first) { + builder.Append(','); + } + + SerializeValue(obj); + + first = false; + } + + builder.Append(']'); + } + + void SerializeString(string str) { + builder.Append('\"'); + + char[] charArray = str.ToCharArray(); + foreach (var c in charArray) { + switch (c) { + case '"': + builder.Append("\\\""); + break; + case '\\': + builder.Append("\\\\"); + break; + case '\b': + builder.Append("\\b"); + break; + case '\f': + builder.Append("\\f"); + break; + case '\n': + builder.Append("\\n"); + break; + case '\r': + builder.Append("\\r"); + break; + case '\t': + builder.Append("\\t"); + break; + default: + int codepoint = Convert.ToInt32(c); + if ((codepoint >= 32) && (codepoint <= 126)) { + builder.Append(c); + } else { + builder.Append("\\u"); + builder.Append(codepoint.ToString("x4")); + } + break; + } + } + + builder.Append('\"'); + } + + void SerializeOther(object value) { + // NOTE: decimals lose precision during serialization. + // They always have, I'm just letting you know. + // Previously floats and doubles lost precision too. + if (value is float) { + builder.Append(((float) value).ToString("R")); + } else if (value is int + || value is uint + || value is long + || value is sbyte + || value is byte + || value is short + || value is ushort + || value is ulong) { + builder.Append(value); + } else if (value is double + || value is decimal) { + builder.Append(Convert.ToDouble(value).ToString("R")); + } else { + SerializeString(value.ToString()); + } + } + } + } +} \ No newline at end of file diff --git a/project/Assets/Myo/Utils/MiniJSON.cs.meta b/project/Assets/Myo/Utils/MiniJSON.cs.meta new file mode 100644 index 0000000..99fcb03 --- /dev/null +++ b/project/Assets/Myo/Utils/MiniJSON.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 33989d3f947c5499cbfa4382908a8f24 +timeCreated: 1435772193 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/MyoUnityIOS/MyoUnityIOS.xcodeproj/project.pbxproj b/project/MyoUnityIOS/MyoUnityIOS.xcodeproj/project.pbxproj new file mode 100644 index 0000000..eee57b2 --- /dev/null +++ b/project/MyoUnityIOS/MyoUnityIOS.xcodeproj/project.pbxproj @@ -0,0 +1,382 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0B3B27381AF2678E0070FFD3 /* libMyoUnityIOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B3B272C1AF2678E0070FFD3 /* libMyoUnityIOS.a */; }; + 0B3B27631AF38C8B0070FFD3 /* MyoSDKBinding.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0B3B27601AF38C8B0070FFD3 /* MyoSDKBinding.mm */; }; + 0B3B27641AF38C8B0070FFD3 /* MyoSDKManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0B3B27621AF38C8B0070FFD3 /* MyoSDKManager.mm */; }; + 0B7FF02E1B02A428002D5D65 /* MyoKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B7FF02D1B02A428002D5D65 /* MyoKit.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 0B3B27391AF2678E0070FFD3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0B3B27241AF2678E0070FFD3 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0B3B272B1AF2678E0070FFD3; + remoteInfo = MyoUnityIOS; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 0B3B272A1AF2678E0070FFD3 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0B3B272C1AF2678E0070FFD3 /* libMyoUnityIOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMyoUnityIOS.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 0B3B27371AF2678E0070FFD3 /* MyoUnityIOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MyoUnityIOSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 0B3B27601AF38C8B0070FFD3 /* MyoSDKBinding.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MyoSDKBinding.mm; sourceTree = ""; }; + 0B3B27611AF38C8B0070FFD3 /* MyoSDKManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyoSDKManager.h; sourceTree = ""; }; + 0B3B27621AF38C8B0070FFD3 /* MyoSDKManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MyoSDKManager.mm; sourceTree = ""; }; + 0B7FF02D1B02A428002D5D65 /* MyoKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MyoKit.framework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0B3B27291AF2678E0070FFD3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0B7FF02E1B02A428002D5D65 /* MyoKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0B3B27341AF2678E0070FFD3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0B3B27381AF2678E0070FFD3 /* libMyoUnityIOS.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0B3B27231AF2678E0070FFD3 = { + isa = PBXGroup; + children = ( + 0B3B272E1AF2678E0070FFD3 /* MyoUnityIOS */, + 0B3B272D1AF2678E0070FFD3 /* Products */, + ); + sourceTree = ""; + }; + 0B3B272D1AF2678E0070FFD3 /* Products */ = { + isa = PBXGroup; + children = ( + 0B3B272C1AF2678E0070FFD3 /* libMyoUnityIOS.a */, + 0B3B27371AF2678E0070FFD3 /* MyoUnityIOSTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 0B3B272E1AF2678E0070FFD3 /* MyoUnityIOS */ = { + isa = PBXGroup; + children = ( + 0BBAADCC1AF3B36000A220E8 /* Frameworks */, + 0B3B27601AF38C8B0070FFD3 /* MyoSDKBinding.mm */, + 0B3B27611AF38C8B0070FFD3 /* MyoSDKManager.h */, + 0B3B27621AF38C8B0070FFD3 /* MyoSDKManager.mm */, + ); + path = MyoUnityIOS; + sourceTree = ""; + }; + 0BBAADCC1AF3B36000A220E8 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 0B7FF02D1B02A428002D5D65 /* MyoKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0B3B272B1AF2678E0070FFD3 /* MyoUnityIOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0B3B27401AF2678E0070FFD3 /* Build configuration list for PBXNativeTarget "MyoUnityIOS" */; + buildPhases = ( + 0B3B27281AF2678E0070FFD3 /* Sources */, + 0B3B27291AF2678E0070FFD3 /* Frameworks */, + 0B3B272A1AF2678E0070FFD3 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MyoUnityIOS; + productName = MyoUnityIOS; + productReference = 0B3B272C1AF2678E0070FFD3 /* libMyoUnityIOS.a */; + productType = "com.apple.product-type.library.static"; + }; + 0B3B27361AF2678E0070FFD3 /* MyoUnityIOSTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0B3B27431AF2678E0070FFD3 /* Build configuration list for PBXNativeTarget "MyoUnityIOSTests" */; + buildPhases = ( + 0B3B27331AF2678E0070FFD3 /* Sources */, + 0B3B27341AF2678E0070FFD3 /* Frameworks */, + 0B3B27351AF2678E0070FFD3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 0B3B273A1AF2678E0070FFD3 /* PBXTargetDependency */, + ); + name = MyoUnityIOSTests; + productName = MyoUnityIOSTests; + productReference = 0B3B27371AF2678E0070FFD3 /* MyoUnityIOSTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0B3B27241AF2678E0070FFD3 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0610; + ORGANIZATIONNAME = "Thalmic Labs"; + TargetAttributes = { + 0B3B272B1AF2678E0070FFD3 = { + CreatedOnToolsVersion = 6.1; + }; + 0B3B27361AF2678E0070FFD3 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 0B3B27271AF2678E0070FFD3 /* Build configuration list for PBXProject "MyoUnityIOS" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 0B3B27231AF2678E0070FFD3; + productRefGroup = 0B3B272D1AF2678E0070FFD3 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0B3B272B1AF2678E0070FFD3 /* MyoUnityIOS */, + 0B3B27361AF2678E0070FFD3 /* MyoUnityIOSTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0B3B27351AF2678E0070FFD3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0B3B27281AF2678E0070FFD3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0B3B27631AF38C8B0070FFD3 /* MyoSDKBinding.mm in Sources */, + 0B3B27641AF38C8B0070FFD3 /* MyoSDKManager.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0B3B27331AF2678E0070FFD3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 0B3B273A1AF2678E0070FFD3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0B3B272B1AF2678E0070FFD3 /* MyoUnityIOS */; + targetProxy = 0B3B27391AF2678E0070FFD3 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 0B3B273E1AF2678E0070FFD3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer: Nelson Andre (SZW6U2YVFM)"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 5.1; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 0B3B273F1AF2678E0070FFD3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer: Nelson Andre (SZW6U2YVFM)"; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 5.1; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0B3B27411AF2678E0070FFD3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/MyoUnityIOS", + ); + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 0B3B27421AF2678E0070FFD3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/MyoUnityIOS", + ); + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 0B3B27441AF2678E0070FFD3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = MyoUnityIOSTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 0B3B27451AF2678E0070FFD3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = MyoUnityIOSTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0B3B27271AF2678E0070FFD3 /* Build configuration list for PBXProject "MyoUnityIOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0B3B273E1AF2678E0070FFD3 /* Debug */, + 0B3B273F1AF2678E0070FFD3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0B3B27401AF2678E0070FFD3 /* Build configuration list for PBXNativeTarget "MyoUnityIOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0B3B27411AF2678E0070FFD3 /* Debug */, + 0B3B27421AF2678E0070FFD3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0B3B27431AF2678E0070FFD3 /* Build configuration list for PBXNativeTarget "MyoUnityIOSTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0B3B27441AF2678E0070FFD3 /* Debug */, + 0B3B27451AF2678E0070FFD3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0B3B27241AF2678E0070FFD3 /* Project object */; +} diff --git a/project/MyoUnityIOS/MyoUnityIOS/MyoSDKBinding.mm b/project/MyoUnityIOS/MyoUnityIOS/MyoSDKBinding.mm new file mode 100644 index 0000000..adfaea2 --- /dev/null +++ b/project/MyoUnityIOS/MyoUnityIOS/MyoSDKBinding.mm @@ -0,0 +1,159 @@ +// +// MyoSDKBindings.m +// HelloMyo +// +// Created by Nelson Andre on 2015-04-24. +// Copyright (c) 2015 Thalmic Labs. All rights reserved. +// + +#import + +#import "MyoSDKManager.h" + +#define CharArrayToStringCopy( _x_ ) ( _x_ != NULL && [_x_ isKindOfClass:[NSString class]] ) ? strdup( [_x_ UTF8String] ) : NULL +#define CharArrayToString( _x_ ) ( _x_ != NULL ) ? [NSString stringWithUTF8String:_x_] : [NSString stringWithUTF8String:""] + +extern "C" +{ + /** + This method is called upon starting the application by myo manager unity game object + **/ + void myo_SetApplicationID(char* app_id){ + + if (app_id == NULL){ + return; + } + + //Convert the unity character array to a NSString + NSString* appId = CharArrayToString(app_id); + [[MyoSDKManager sharedManager] setApplicationID:appId]; + } + + void myo_SetShouldNotifyInBackground(bool value){ + [[TLMHub sharedHub] setShouldNotifyInBackground:value]; + } + + void myo_SetShouldSendUsageData(bool value){ + [[TLMHub sharedHub] setShouldSendUsageData:value]; + } + + + bool myo_VibrateWithLength(char* myoId, int length){ + + NSString* myoIdString = CharArrayToString(myoId); + + for (TLMMyo* myo in [[TLMHub sharedHub] myoDevices]) + { + + if ([[[myo identifier] UUIDString] isEqualToString:myoIdString ]) + { + [myo vibrateWithLength:(TLMVibrationLength) length]; + return true; + } + } + return false; + } + + + + bool myo_SetStreamEmg(char *myoId, int type){ + + NSString* myoIdString = CharArrayToString(myoId); + + for (TLMMyo* myo in [[TLMHub sharedHub] myoDevices]) + { + + if ([[[myo identifier] UUIDString] isEqualToString:myoIdString ]) + { + [myo setStreamEmg:(TLMStreamEmgType)type]; + return true; + } + } + + return false; + } + + bool myo_IndicateUserAction(char *myoId){ + + NSString* myoIdString = CharArrayToString(myoId); + + for (TLMMyo* myo in [[TLMHub sharedHub] myoDevices]) + { + + if ([[[myo identifier] UUIDString] isEqualToString:myoIdString ]) + { + [myo indicateUserAction]; + return true; + } + } + + return false; + } + + + int myo_MyoConnectionAllowance(){ + + return [[TLMHub sharedHub] myoConnectionAllowance]; + } + + void myo_SetMyoConnectionAllowance(int value){ + + NSLog(@"Set myo connection allowance to be %d", value); + + [[TLMHub sharedHub] setMyoConnectionAllowance:value]; + } + + bool myo_Lock(char *myoId){ + NSString* myoIdString = CharArrayToString(myoId); + + for (TLMMyo* myo in [[TLMHub sharedHub] myoDevices]) + { + + if ([[[myo identifier] UUIDString] isEqualToString:myoIdString ]) + { + [myo lock]; + return true; + } + } + + return false; + } + + bool myo_UnlockWithType(char* myoId, int type){ + + NSString* myoIdString = CharArrayToString(myoId); + + for (TLMMyo* myo in [[TLMHub sharedHub] myoDevices]) + { + + if ([[[myo identifier] UUIDString] isEqualToString:myoIdString ]) + { + [myo unlockWithType:(TLMUnlockType)type]; + return true; + } + } + return false; + } + + + void myo_ShowSettings(){ + [[MyoSDKManager sharedManager] showSettings]; + } + + bool myo_IsArmLocked(){ + + return [[MyoSDKManager sharedManager] locked]; + } + + void myo_SetLockingPolicy(int policy){ + + [[MyoSDKManager sharedManager] setLockingPolicy:policy]; + } + + const char* myo_GetMyos(){ + NSString* result = [[MyoSDKManager sharedManager] getMyoDevices]; + + return [result UTF8String]; + } + +} \ No newline at end of file diff --git a/project/MyoUnityIOS/MyoUnityIOS/MyoSDKManager.h b/project/MyoUnityIOS/MyoUnityIOS/MyoSDKManager.h new file mode 100644 index 0000000..28bce91 --- /dev/null +++ b/project/MyoUnityIOS/MyoUnityIOS/MyoSDKManager.h @@ -0,0 +1,35 @@ +// +// MyoSDKManager.h +// HelloMyo +// +// Created by Nelson Andre on 2015-04-24. +// Copyright (c) 2015 Thalmic Labs. All rights reserved. +// + + +#import + +enum Status +{ + WAITING, + CONNECTED +}; + +@interface MyoSDKManager : NSObject +{ + +} + +- (void) setApplicationID: (NSString*) appID; +- (void) showSettings; +- (void) setLockingPolicy: (int) policy; +- (NSString*) getMyoDevices; + +@property (nonatomic) Status status; + +@property (nonatomic) BOOL locked; + +@property (nonatomic) TLMArmXDirection armXDirection; + ++ (MyoSDKManager*)sharedManager; +@end \ No newline at end of file diff --git a/project/MyoUnityIOS/MyoUnityIOS/MyoSDKManager.mm b/project/MyoUnityIOS/MyoUnityIOS/MyoSDKManager.mm new file mode 100644 index 0000000..7c9d377 --- /dev/null +++ b/project/MyoUnityIOS/MyoUnityIOS/MyoSDKManager.mm @@ -0,0 +1,365 @@ +// +// MyoUnitySDK +// +// Created by Nelson Andre on 2015-04-24. +// Copyright (c) 2015 Thalmic Labs. All rights reserved. +// + +#import +#import "MyoSDKManager.h" + +#import + +#import + +@implementation MyoSDKManager + +void UnityPause( bool pause ); + +extern "C" void UnitySendMessage( const char * className, const char * methodName, const char * param ); + +extern "C" UIViewController *UnityGetGLViewController(); + +#define MYO_UNITY_GAMEOBJECT "MyoIOSManager" + ++ (MyoSDKManager*)sharedManager +{ + static MyoSDKManager *sharedManager = nil; + + if( !sharedManager ) + sharedManager = [[MyoSDKManager alloc] init]; + + return sharedManager; +} + +- (id)init +{ + if( ( self = [super init] ) ) + { + [self subscribeToNotifications]; + } + return self; +} + +- (void) subscribeToNotifications { + + NSLog(@"Subscribing to Myo Notifications"); + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didConnectDevice:) + name:TLMHubDidConnectDeviceNotification + object:nil]; + // Posted whenever a TLMMyo disconnects. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didDisconnectDevice:) + name:TLMHubDidDisconnectDeviceNotification + object:nil]; + // Posted whenever the user does a successful Sync Gesture. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didSyncArm:) + name:TLMMyoDidReceiveArmSyncEventNotification + object:nil]; + // Posted whenever Myo loses sync with an arm (when Myo is taken off, or moved enough on the user's arm). + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didUnsyncArm:) + name:TLMMyoDidReceiveArmUnsyncEventNotification + object:nil]; + // Posted whenever Myo is unlocked and the application uses TLMLockingPolicyStandard. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didUnlockDevice:) + name:TLMMyoDidReceiveUnlockEventNotification + object:nil]; + // Posted whenever Myo is locked and the application uses TLMLockingPolicyStandard. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didLockDevice:) + name:TLMMyoDidReceiveLockEventNotification + object:nil]; + // Posted when a new orientation event is available from a TLMMyo. Notifications are posted at a rate of 50 Hz. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveOrientationEvent:) + name:TLMMyoDidReceiveOrientationEventNotification + object:nil]; + // Posted when a new accelerometer event is available from a TLMMyo. Notifications are posted at a rate of 50 Hz. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveAccelerometerEvent:) + name:TLMMyoDidReceiveAccelerometerEventNotification + object:nil]; + + // Posted when a new accelerometer event is available from a TLMMyo. Notifications are posted at a rate of 50 Hz. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveGyroscopeEvent:) + name:TLMMyoDidReceiveGyroscopeEventNotification + object:nil]; + + // Posted when a new pose is available from a TLMMyo. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceivePoseChange:) + name:TLMMyoDidReceivePoseChangedNotification + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver: self + selector: + @selector(didReceiveEmgEvent:) + name:TLMMyoDidReceiveEmgEventNotification + object:nil]; +} + +#pragma mark - NSNotificationCenter Methods +-(void) didReceiveEmgEvent:(NSNotification*) notification{ + + TLMEmgEvent* event = notification.userInfo[kTLMKeyEMGEvent]; + + NSMutableDictionary* eventDictionary = [NSMutableDictionary new]; + + eventDictionary[@"myoIdentifier"] = [event.myo.identifier UUIDString]; + eventDictionary[@"rawData"] = event.rawData; + + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didReceiveEmgEvent", [[self dictToJSON:eventDictionary] UTF8String] ); +} + + + +- (void)didConnectDevice:(NSNotification *)notification { + + TLMMyo* myo = notification.userInfo[kTLMKeyMyo]; + + NSMutableDictionary* eventDictionary = [NSMutableDictionary new]; + eventDictionary[@"myoIdentifier"] = [myo.identifier UUIDString]; + + self.status = CONNECTED; + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didConnectDevice", [[self dictToJSON:eventDictionary] UTF8String]); +} + +- (void)didDisconnectDevice:(NSNotification *)notification { + self.status = WAITING; + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didDisconnectDevice", "" ); +} + +- (void)didUnlockDevice:(NSNotification *)notification { + + TLMUnlockEvent *event = notification.userInfo[kTLMKeyUnlockEvent]; + + NSDictionary* eventDictionary = @{@"myoIdentifier": [event.myo.identifier UUIDString], + }; + + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didUnlockDevice", [[self dictToJSON:eventDictionary] UTF8String] ); +} + +- (void)didLockDevice:(NSNotification *)notification { + TLMLockEvent *event = notification.userInfo[kTLMKeyLockEvent]; + + NSDictionary* eventDictionary = @{@"myoIdentifier": [event.myo.identifier UUIDString], + + }; + + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didLockDevice", [[self dictToJSON:eventDictionary] UTF8String] ); +} + +- (void)didSyncArm:(NSNotification *)notification { + + + TLMArmSyncEvent *event = notification.userInfo[kTLMKeyArmSyncEvent]; + + NSDictionary* eventDictionary = @{@"myoIdentifier": [event.myo.identifier UUIDString], + + @"armXDirection": [NSNumber numberWithInt:(int)event.xDirection] + }; + + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didSyncArm", [[self dictToJSON:eventDictionary] UTF8String]); +} + +- (void)didUnsyncArm:(NSNotification *)notification { + + TLMArmUnsyncEvent* event = notification.userInfo[kTLMKeyArmUnsyncEvent]; + + NSDictionary* eventDictionary = @{@"myoIdentifier": [event.myo.identifier UUIDString], + + }; + + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didUnsyncArmEvent", [[self dictToJSON:eventDictionary] UTF8String] ); +} + +-(NSString*) dictToJSON: (NSDictionary*) dictionary +{ + NSError *error; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary + options:0 + error:&error]; + + if (!jsonData) return NULL; + + return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + +} + + +- (void) didReceiveGyroscopeEvent: (NSNotification*) notification { + + + TLMGyroscopeEvent* event = notification.userInfo[kTLMKeyGyroscopeEvent]; + + // Get the acceleration vector from the accelerometer event. + TLMVector3 accelerationVector = event.vector; + + NSDictionary* eventDictionary = @{ + @"vector": @{@"x": [NSNumber numberWithFloat: accelerationVector.x], + @"y": [NSNumber numberWithFloat: accelerationVector.y], + @"z": [NSNumber numberWithFloat: accelerationVector.z] + }, + @"myoIdentifier":[event.myo.identifier UUIDString], + + }; + + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didReceiveGyroscopeEvent", [[self dictToJSON:eventDictionary] UTF8String] ); +} + +- (void)didReceiveOrientationEvent:(NSNotification *)notification { + // Retrieve the orientation from the NSNotification's userInfo with the kTLMKeyOrientationEvent key. + TLMOrientationEvent *orientationEvent = notification.userInfo[kTLMKeyOrientationEvent]; + TLMQuaternion quaternion = orientationEvent.quaternion; + + NSDictionary* eventDictionary = @{ + @"quaternion": @{@"x": [NSNumber numberWithFloat: quaternion.x], + @"y": [NSNumber numberWithFloat: quaternion.y], + @"z": [NSNumber numberWithFloat: quaternion.z], + @"w": [NSNumber numberWithFloat: quaternion.w] + }, + @"myoIdentifier":[orientationEvent.myo.identifier UUIDString], + + }; + + + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didReceiveOrientationEvent", [[self dictToJSON:eventDictionary] UTF8String] ); +} + +- (void)didReceiveAccelerometerEvent:(NSNotification *)notification { + + //maybe want to have this be tied to the references to the accelerometer values... + // Retrieve the accelerometer event from the NSNotification's userInfo with the kTLMKeyAccelerometerEvent. + TLMAccelerometerEvent *accelerometerEvent = notification.userInfo[kTLMKeyAccelerometerEvent]; + + // Get the acceleration vector from the accelerometer event. + TLMVector3 accelerationVector = accelerometerEvent.vector; + + NSDictionary* eventDictionary = @{ + @"acceleration": @{@"x": [NSNumber numberWithFloat: accelerationVector.x], + @"y": [NSNumber numberWithFloat: accelerationVector.y], + @"z": [NSNumber numberWithFloat: accelerationVector.z] + }, + @"myoIdentifier":[accelerometerEvent.myo.identifier UUIDString], + + }; + + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didReceiveAccelerometerEvent", [[self dictToJSON:eventDictionary] UTF8String] ); +} + +- (void)didReceivePoseChange:(NSNotification *)notification { + + TLMPose *pose = notification.userInfo[kTLMKeyPose]; + + NSString* poseString = @""; + + switch (pose.type) { + case TLMPoseTypeUnknown: + poseString = @"Unknown"; + break; + + case TLMPoseTypeRest: + poseString = @"Rest"; + break; + + case TLMPoseTypeDoubleTap: + poseString = @"DoubleTap"; + break; + + case TLMPoseTypeFist: + poseString = @"Fist"; + break; + + case TLMPoseTypeWaveIn: + poseString = @"WaveOut"; + break; + + case TLMPoseTypeWaveOut: + poseString = @"WaveOut"; + break; + case TLMPoseTypeFingersSpread: + poseString = @"FingersSpread"; + break; + } + + const char* params = [poseString UTF8String]; + + UnitySendMessage( MYO_UNITY_GAMEOBJECT, "didReceivePoseChange", params ); +} + +#pragma mark Public methods + + + +//This method returns a json representation of the myo devices to unity as a string +-(NSString*) getMyoDevices +{ + NSArray* myoDevices = [[TLMHub sharedHub] myoDevices]; + + NSMutableDictionary* resultDictionary = [NSMutableDictionary dictionary]; + + //Serialize the myo object into a dictionary to be converted to json to be deserialized by unity + for (TLMMyo* myo : myoDevices) + { + NSMutableDictionary* myoDictionary = [NSMutableDictionary dictionary]; + resultDictionary[@"name"] = myo.name; + resultDictionary[@"identifier"] = myo.identifier; + resultDictionary[@"state"] = [NSNumber numberWithInt:myo.state]; + resultDictionary[@"isLocked"] = [NSNumber numberWithBool:myo.isLocked]; + + NSMutableDictionary* poseDictionary = [NSMutableDictionary dictionary]; + poseDictionary[@"type"] = [NSNumber numberWithInt:myo.pose.type]; + + resultDictionary[@"pose"] = poseDictionary; + + + NSMutableDictionary* orientationDictionary = [NSMutableDictionary dictionary]; + + NSMutableDictionary* quaternionDict = [NSMutableDictionary dictionary]; + + quaternionDict[@"x"] = [NSNumber numberWithFloat:myo.orientation.quaternion.x]; + quaternionDict[@"y"] = [NSNumber numberWithFloat:myo.orientation.quaternion.y]; + quaternionDict[@"z"] = [NSNumber numberWithFloat:myo.orientation.quaternion.z]; + quaternionDict[@"w"] = [NSNumber numberWithFloat:myo.orientation.quaternion.w]; + orientationDictionary[@"data"] = quaternionDict; + resultDictionary[@"orientation"] = orientationDictionary; + + resultDictionary[@"arm"] = [NSNumber numberWithInt:myo.arm]; + resultDictionary[@"xDirection"] = [NSNumber numberWithInt:myo.xDirection]; + resultDictionary[myo.identifier] = myoDictionary; + } + NSError* error = nil; + + NSData* data = [NSJSONSerialization dataWithJSONObject:resultDictionary options:0 error:&error]; + + return [[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding]; +} + +-(void) setLockingPolicy: (int) policy { + + [[TLMHub sharedHub] setLockingPolicy:(TLMLockingPolicy)policy]; +} + +- (void) showSettings{ + + // Note that when the settings view controller is presented to the user, it must be in a UINavigationController. + UINavigationController *controller = [TLMSettingsViewController settingsInNavigationController]; + // Present the settings view controller modally. + + UIViewController* unityController = UnityGetGLViewController(); + + [unityController presentViewController:controller animated:YES completion:nil]; +} + +- (void) setApplicationID: (NSString*) appID{ + [[TLMHub sharedHub] setApplicationIdentifier:appID]; +} + +@end + diff --git a/project/MyoUnityIOS/MyoUnityIOSTests/Info.plist.meta b/project/MyoUnityIOS/MyoUnityIOSTests/Info.plist.meta new file mode 100644 index 0000000..6183249 --- /dev/null +++ b/project/MyoUnityIOS/MyoUnityIOSTests/Info.plist.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 49e91ba2f36cc4971acd136f6b285170 +timeCreated: 1430401085 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/project/ProjectSettings/EditorBuildSettings.asset b/project/ProjectSettings/EditorBuildSettings.asset index 6dc24f7..1260ac1 100644 --- a/project/ProjectSettings/EditorBuildSettings.asset +++ b/project/ProjectSettings/EditorBuildSettings.asset @@ -4,4 +4,6 @@ EditorBuildSettings: m_ObjectHideFlags: 0 serializedVersion: 2 - m_Scenes: [] + m_Scenes: + - enabled: 1 + path: Assets/Myo Samples/Box On A Stick.unity diff --git a/project/ProjectSettings/GraphicsSettings.asset b/project/ProjectSettings/GraphicsSettings.asset index 553f97d..280a9fd 100644 --- a/project/ProjectSettings/GraphicsSettings.asset +++ b/project/ProjectSettings/GraphicsSettings.asset @@ -3,5 +3,27 @@ --- !u!30 &1 GraphicsSettings: m_ObjectHideFlags: 0 + serializedVersion: 3 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_LegacyDeferred: + m_Mode: 1 + m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} m_AlwaysIncludedShaders: - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10782, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_LightmapStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDirSeparate: 1 + m_LightmapKeepDynamic: 1 + m_FogStripping: 0 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 diff --git a/project/ProjectSettings/ProjectSettings.asset b/project/ProjectSettings/ProjectSettings.asset index 7edec76..885ee8d 100644 --- a/project/ProjectSettings/ProjectSettings.asset +++ b/project/ProjectSettings/ProjectSettings.asset @@ -3,17 +3,17 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 2 + serializedVersion: 7 AndroidProfiler: 0 defaultScreenOrientation: 0 targetDevice: 2 - targetGlesGraphics: 1 targetResolution: 0 accelerometerFrequency: 60 companyName: DefaultCompany productName: myo-unity-sdk-project defaultCursor: {fileID: 0} cursorHotspot: {x: 0, y: 0} + m_ShowUnitySplashScreen: 1 defaultScreenWidth: 1024 defaultScreenHeight: 768 defaultScreenWidthWeb: 960 @@ -23,9 +23,10 @@ PlayerSettings: m_ActiveColorSpace: 0 m_MTRendering: 1 m_MobileMTRendering: 0 - m_UseDX11: 0 + m_Stereoscopic3D: 0 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 + iosAppInBackgroundBehavior: 0 displayResolutionDialog: 1 allowedAutorotateToPortrait: 1 allowedAutorotateToPortraitUpsideDown: 1 @@ -33,16 +34,16 @@ PlayerSettings: allowedAutorotateToLandscapeLeft: 1 useOSAutorotation: 1 use32BitDisplayBuffer: 1 - use24BitDepthBuffer: 1 + disableDepthAndStencilBuffers: 0 defaultIsFullScreen: 1 defaultIsNativeResolution: 1 runInBackground: 0 captureSingleScreen: 0 Override IPod Music: 0 Prepare IOS For Recording: 0 - enableHWStatistics: 1 + submitAnalytics: 1 usePlayerLog: 1 - stripPhysics: 0 + bakeCollisionMeshes: 0 forceSingleInstance: 0 resizableWindow: 0 useMacAppStoreValidation: 0 @@ -52,32 +53,32 @@ PlayerSettings: xboxEnableKinect: 0 xboxEnableKinectAutoTracking: 0 xboxEnableFitness: 0 + visibleInBackground: 0 macFullscreenMode: 2 + d3d9FullscreenMode: 1 + d3d11FullscreenMode: 1 xboxSpeechDB: 0 xboxEnableHeadOrientation: 0 xboxEnableGuest: 0 - wiiHio2Usage: -1 - wiiLoadingScreenRectPlacement: 0 - wiiLoadingScreenBackground: {r: 1, g: 1, b: 1, a: 1} - wiiLoadingScreenPeriod: 1000 - wiiLoadingScreenFileName: - wiiLoadingScreenRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 0 - height: 0 + xboxOneResolution: 0 + ps3SplashScreen: {fileID: 0} + videoMemoryForVertexBuffers: 0 + psp2PowerMode: 0 + psp2AcquireBGM: 1 m_SupportedAspectRatios: 4:3: 1 5:4: 1 16:10: 1 16:9: 1 Others: 1 - iPhoneBundleIdentifier: com.Company.ProductName + bundleIdentifier: com.Company.ProductName + bundleVersion: 1.0 + preloadedAssets: [] metroEnableIndependentInputSource: 0 metroEnableLowLatencyPresentationAPI: 0 + xboxOneDisableKinectGpuReservation: 0 + virtualRealitySupported: 0 productGUID: 3d3757977f4fd44a0be0d36f05982085 - iPhoneBundleVersion: 1.0 AndroidBundleVersionCode: 1 AndroidMinSdkVersion: 9 AndroidPreferredInstallLocation: 1 @@ -89,9 +90,10 @@ PlayerSettings: ForceSDCardPermission: 0 CreateWallpaper: 0 APKExpansionFiles: 0 + preloadShaders: 0 StripUnusedMeshComponents: 0 iPhoneSdkVersion: 988 - iPhoneTargetOSVersion: 16 + iPhoneTargetOSVersion: 22 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIStatusBarHidden: 1 @@ -100,30 +102,56 @@ PlayerSettings: iPhoneSplashScreen: {fileID: 0} iPhoneHighResSplashScreen: {fileID: 0} iPhoneTallHighResSplashScreen: {fileID: 0} + iPhone47inSplashScreen: {fileID: 0} + iPhone55inPortraitSplashScreen: {fileID: 0} + iPhone55inLandscapeSplashScreen: {fileID: 0} iPadPortraitSplashScreen: {fileID: 0} iPadHighResPortraitSplashScreen: {fileID: 0} iPadLandscapeSplashScreen: {fileID: 0} iPadHighResLandscapeSplashScreen: {fileID: 0} + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreenCustomXibPath: AndroidTargetDevice: 0 AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} AndroidKeystoreName: AndroidKeyaliasName: + AndroidTVCompatibility: 1 + AndroidIsGame: 1 + androidEnableBanner: 1 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 resolutionDialogBanner: {fileID: 0} - m_BuildTargetIcons: [] + m_BuildTargetIcons: + - m_BuildTarget: + m_Icons: + - m_Icon: {fileID: 0} + m_Size: 128 m_BuildTargetBatching: [] + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: WindowsStandaloneSupport + m_APIs: 01000000 + m_Automatic: 0 + - m_BuildTarget: AndroidPlayer + m_APIs: 08000000 + m_Automatic: 0 webPlayerTemplate: APPLICATION:Default m_TemplateCustomTags: {} - wiiRegion: 1 - wiiGameCode: RABA - wiiGameVersion: - wiiCompanyCode: ZZ - wiiSupportsNunchuk: 0 - wiiSupportsClassicController: 0 - wiiSupportsBalanceBoard: 0 - wiiSupportsMotionPlus: 0 - wiiControllerCount: 1 - wiiFloatingPointExceptions: 0 - wiiScreenCrashDumps: 1 + actionOnDotNetUnhandledException: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + locationUsageDescription: XboxTitleId: XboxImageXexPath: XboxSpaPath: @@ -139,6 +167,7 @@ PlayerSettings: ps3ThumbnailPath: ps3BackgroundPath: ps3SoundPath: + ps3NPAgeRating: 12 ps3TrophyCommId: ps3NpCommunicationPassphrase: ps3TrophyPackagePath: @@ -146,11 +175,99 @@ PlayerSettings: ps3TrophyCommSig: ps3SaveGameSlots: 1 ps3TrialMode: 0 - flashStrippingLevel: 2 + ps3VideoMemoryForAudio: 0 + ps3EnableVerboseMemoryStats: 0 + ps3UseSPUForUmbra: 0 + ps3EnableMoveSupport: 1 + ps3DisableDolbyEncoding: 0 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 1 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutResolution: 4 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4SaveDataImagePath: + ps4BGMPath: + ps4ShareFilePath: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4EnterButtonAssignment: 1 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4GarlicHeapSize: 2048 + ps4Passcode: 5xr84P2R391UXaLHbavJvFZGfO47XWS2 + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + monoEnv: + psp2Splashimage: {fileID: 0} + psp2NPTrophyPackPath: + psp2NPSupportGBMorGJP: 0 + psp2NPAgeRating: 12 + psp2NPTitleDatPath: + psp2NPCommsID: + psp2NPCommunicationsID: + psp2NPCommsPassphrase: + psp2NPCommsSig: + psp2ParamSfxPath: + psp2ManualPath: + psp2LiveAreaGatePath: + psp2LiveAreaBackroundPath: + psp2LiveAreaPath: + psp2LiveAreaTrialPath: + psp2PatchChangeInfoPath: + psp2PatchOriginalPackage: + psp2PackagePassword: qVOw5lxuBEBNue7b9PZS0hoI6pgabi9U + psp2KeystoneFile: + psp2MemoryExpansionMode: 0 + psp2DRMType: 0 + psp2StorageType: 0 + psp2MediaCapacity: 0 + psp2DLCConfigPath: + psp2ThumbnailPath: + psp2BackgroundPath: + psp2SoundPath: + psp2TrophyCommId: + psp2TrophyPackagePath: + psp2PackagedResourcesPath: + psp2SaveDataQuota: 10240 + psp2ParentalLevel: 1 + psp2ShortTitle: Not Set + psp2ContentID: IV0000-ABCD12345_00-0123456789ABCDEF + psp2Category: 0 + psp2MasterVersion: 01.00 + psp2AppVersion: 01.00 + psp2TVBootMode: 0 + psp2EnterButtonAssignment: 2 + psp2TVDisableEmu: 0 + psp2AllowTwitterDialog: 1 + psp2Upgradable: 0 + psp2HealthWarning: 0 + psp2UseLibLocation: 0 + psp2InfoBarOnStartup: 0 + psp2InfoBarColor: 0 + psmSplashimage: {fileID: 0} spritePackerPolicy: scriptingDefineSymbols: {} metroPackageName: myo-unity-sdk-project metroPackageLogo: + metroPackageLogo140: + metroPackageLogo180: + metroPackageLogo240: metroPackageVersion: metroCertificatePath: metroCertificatePassword: @@ -158,19 +275,59 @@ PlayerSettings: metroCertificateIssuer: metroCertificateNotAfter: 0000000000000000 metroApplicationDescription: myo-unity-sdk-project - metroTileLogo: - metroTileWideLogo: - metroTileSmallLogo: + metroStoreTileLogo80: + metroStoreTileLogo: + metroStoreTileLogo140: + metroStoreTileLogo180: + metroStoreTileWideLogo80: + metroStoreTileWideLogo: + metroStoreTileWideLogo140: + metroStoreTileWideLogo180: + metroStoreTileSmallLogo80: + metroStoreTileSmallLogo: + metroStoreTileSmallLogo140: + metroStoreTileSmallLogo180: + metroStoreSmallTile80: + metroStoreSmallTile: + metroStoreSmallTile140: + metroStoreSmallTile180: + metroStoreLargeTile80: + metroStoreLargeTile: + metroStoreLargeTile140: + metroStoreLargeTile180: + metroStoreSplashScreenImage: + metroStoreSplashScreenImage140: + metroStoreSplashScreenImage180: + metroPhoneAppIcon: + metroPhoneAppIcon140: + metroPhoneAppIcon240: + metroPhoneSmallTile: + metroPhoneSmallTile140: + metroPhoneSmallTile240: + metroPhoneMediumTile: + metroPhoneMediumTile140: + metroPhoneMediumTile240: + metroPhoneWideTile: + metroPhoneWideTile140: + metroPhoneWideTile240: + metroPhoneSplashScreenImage: + metroPhoneSplashScreenImage140: + metroPhoneSplashScreenImage240: metroTileShortName: metroCommandLineArgsFile: metroTileShowName: 1 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroDefaultTileSize: 1 metroTileForegroundText: 1 metroTileBackgroundColor: {r: 0, g: 0, b: 0, a: 1} - metroSplashScreenImage: metroSplashScreenBackgroundColor: {r: 0, g: 0, b: 0, a: 1} metroSplashScreenUseBackgroundColor: 0 - metroCapabilities: {} - metroUnprocessedPlugins: [] + platformCapabilities: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: metroCompilationOverrides: 1 blackberryDeviceAddress: blackberryDevicePassword: @@ -178,10 +335,8 @@ PlayerSettings: blackberryTokenExires: blackberryTokenAuthor: blackberryTokenAuthorId: - blackberryAuthorId: blackberryCskPassword: blackberrySaveLogPath: - blackberryAuthorIdOveride: 0 blackberrySharedPermissions: 0 blackberryCameraPermissions: 0 blackberryGPSPermissions: 0 @@ -194,10 +349,61 @@ PlayerSettings: blackberrySquareSplashScreen: {fileID: 0} tizenProductDescription: tizenProductURL: - tizenCertificatePath: - tizenCertificatePassword: - tizenSaveLogPath: - firstStreamedLevelWithResources: 0 - unityRebuildLibraryVersion: 9 - unityForwardCompatibleVersion: 39 - unityStandardAssetsVersion: 0 + tizenSigningProfileName: + tizenGPSPermissions: 0 + tizenMicrophonePermissions: 0 + stvDeviceAddress: + stvProductDescription: + stvProductAuthor: + stvProductAuthorEmail: + stvProductLink: + stvProductCategory: 0 + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneIsContentPackage: 0 + XboxOneEnableGPUVariability: 0 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + intPropertyNames: + - WebGL::ScriptingBackend + - WebGL::audioCompressionFormat + - WebGL::exceptionSupport + - WebGL::memorySize + - iOS::Architecture + - iOS::ScriptingBackend + WebGL::ScriptingBackend: 1 + WebGL::audioCompressionFormat: 4 + WebGL::exceptionSupport: 1 + WebGL::memorySize: 256 + iOS::Architecture: 0 + iOS::ScriptingBackend: 0 + boolPropertyNames: + - WebGL::analyzeBuildSize + - WebGL::dataCaching + - WebGL::useEmbeddedResources + WebGL::analyzeBuildSize: 0 + WebGL::dataCaching: 0 + WebGL::useEmbeddedResources: 0 + stringPropertyNames: + - WebGL::emscriptenArgs + - WebGL::template + WebGL::emscriptenArgs: + WebGL::template: APPLICATION:Default + firstStreamedSceneWithResources: 0 + cloudProjectId: + projectId: + projectName: + organizationId: + cloudEnabled: 0