Main Site Documentation

Touch C8 not in Gadgeteer toolbox


#1

Just got a Touch C8. Is there an update to Gadgeteer that will enable this module? I downloaded the latest but I can’t add it to my gadgeteer project. Alternatively, Is there a manual way to use it with plain old .Net MF 4.2?


#2

Nevermind. It was introduced after the latest release. Probably going to be in the next release.


#3

Yes it will be in the new SDK (coming very soon), here is the driver

using System.Threading;
using Microsoft.SPOT.Hardware;
using GT = Gadgeteer;
using GTI = Gadgeteer.Interfaces;

namespace Gadgeteer.Modules.GHIElectronics
{
	/// <summary>
	/// A multi-function touch sensor for .Net Gadgeteer.
	/// </summary>
	public class TouchC8 : GT.Modules.Module
	{
		private const ushort I2C_ADDRESS = 0x2B;
		private const int I2C_CLOCK_RATE = 100;

		private const byte IRQ_SRC = 0x0;
		private const byte CAP_STAT_MSB = 0x1;
		private const byte CAP_STAT_LSB = 0x2;
		private const byte WHL_POS_MSB = 0x3;
		private const byte WHL_POS_LSB = 0x4;

		private const byte WHEELS = 8;

		private GT.Socket socket;
		private GTI.I2CBus device;
		private GTI.InterruptInput interrupt;
		private GTI.DigitalOutput reset;

		private byte[] readBuffer;
		private byte[] writeBuffer;
		private byte[] addressBuffer;

		private Direction previousWheelDirection;
		private double previousWheelPosition;
		private bool previousWheelTouched;
		private bool previousButton0Touched;
		private bool previousButton1Touched;
		private bool previousButton2Touched;
		private bool previousButton3Touched;

		/// <summary>
		/// Represents the buttons on the sensor.
		/// </summary>
		public enum Buttons
		{
			/// <summary>
			/// The up button.
			/// </summary>
			Up = 0x2,
			/// <summary>
			/// The middle button.
			/// </summary>
			Middle = 0x4,
			/// <summary>
			/// The down button.
			/// </summary>
			Down = 0x8
		}

		/// <summary>
		/// Represents the direction of motion on the wheel.
		/// </summary>
		public enum Direction
		{
			/// <summary>
			/// Clockwise motion
			/// </summary>
			Clockwise,
			/// <summary>
			/// Counterclockwise motion
			/// </summary>
			Counterclockwise
		}

		/// <summary>
		/// Delegate representing the proximity detected event.
		/// </summary>
		/// <param name="sender">The sensor that the detection occured on.</param>
		/// <param name="state">Whether or not an object is near the sensor.</param>
		public delegate void PromixityDetectedHandler(TouchC8 sender, bool state);

		/// <summary>
		/// Delegate representing the button touch event.
		/// </summary>
		/// <param name="sender">The sensor that the event occured on.</param>
		/// <param name="button">The button that the event occured on.</param>
		/// <param name="state">Whether or not the button was pressed or released.</param>
		public delegate void ButtonTouchHandler(TouchC8 sender, Buttons button, bool state);

		/// <summary>
		/// Delegate representing the wheel touch event.
		/// </summary>
		/// <param name="sender">The sensor that the event occured on.</param>
		/// <param name="state">Whether or not the wheel was pressed or released.</param>
		public delegate void WheelTouchHandler(TouchC8 sender, bool state);

		/// <summary>
		/// Delegate representing the wheel position changed event.
		/// </summary>
		/// <param name="sender">The sensor that the event occured on.</param>
		/// <param name="position">The position of the touch on the wheel.</param>
		/// <param name="direction">The direction of the touch on the wheel.</param>
		public delegate void WheelPositionChangedHandler(TouchC8 sender, double position, Direction direction);

		/// <summary>
		/// Fires when the proximity sensor detects an object.
		/// </summary>
		public event PromixityDetectedHandler OnProximityEnter;

		/// <summary>
		/// Fires when the proximity sensor no longer detects an object after detecting one.
		/// </summary>
		public event PromixityDetectedHandler OnProximityExit;

		/// <summary>
		/// Fires when a button is pressed.
		/// </summary>
		public event ButtonTouchHandler OnButtonPressed;

		/// <summary>
		/// Fires when a button is released.
		/// </summary>
		public event ButtonTouchHandler OnButtonReleased;

		/// <summary>
		/// Fires when the wheel is pressed.
		/// </summary>
		public event WheelTouchHandler OnWheelPressed;

		/// <summary>
		/// Fires when the wheel is released.
		/// </summary>
		public event WheelTouchHandler OnWheelReleased;

		/// <summary>
		/// Fires when the position of the touch on the wheel changes.
		/// </summary>
		public event WheelPositionChangedHandler OnWheelPositionChanged;

		private PromixityDetectedHandler OnProximity;
		private ButtonTouchHandler OnButton;
		private WheelTouchHandler OnWheel;
		private WheelPositionChangedHandler OnWheelPosition;

		private void OnProximityEvent(TouchC8 sender, bool state)
		{
			if (this.OnProximity == null)
				this.OnProximity = new PromixityDetectedHandler(this.OnProximityEvent);

			if (Program.CheckAndInvoke(state ? this.OnProximityEnter : this.OnProximityExit, this.OnProximity, sender, state))
			{
				if (state)
					this.OnProximityEnter(sender, state);
				else
					this.OnProximityExit(sender, state);
			}
		}

		private void OnButtonEvent(TouchC8 sender, Buttons button, bool state)
		{
			if (this.OnButton == null)
				this.OnButton = new ButtonTouchHandler(this.OnButtonEvent);

			if (Program.CheckAndInvoke(state ? this.OnButtonPressed : this.OnButtonReleased, this.OnButton, sender, button, state))
			{
				if (state)
					this.OnButtonPressed(sender, button, state);
				else
					this.OnButtonReleased(sender, button, state);
			}
		}

		private void OnWheelEvent(TouchC8 sender, bool state)
		{
			if (this.OnWheel == null)
				this.OnWheel = new WheelTouchHandler(this.OnWheelEvent);

			if (Program.CheckAndInvoke(state ? this.OnWheelPressed : this.OnWheelReleased, this.OnWheel, sender, state))
			{
				if (state)
					this.OnWheelPressed(sender, state);
				else
					this.OnWheelReleased(sender, state);
			}
		}

		private void OnWheelPositionEvent(TouchC8 sender, double position, Direction direction)
		{
			if (this.OnWheelPosition == null)
				this.OnWheelPosition = new WheelPositionChangedHandler(this.OnWheelPositionEvent);

			if (Program.CheckAndInvoke(this.OnWheelPositionChanged, this.OnWheelPosition, sender, position, direction))
				this.OnWheelPositionChanged(sender, position, direction);
		}

		/// <summary>
		/// Constructs a new TouchC8 sensor.
		/// </summary>
		/// <param name="socketNumber">The socket number the sensor is plugged into.</param>
		public TouchC8(int socketNumber)
		{
			this.readBuffer = new byte[1];
			this.writeBuffer = new byte[2];
			this.addressBuffer = new byte[1];

			this.socket = GT.Socket.GetSocket(socketNumber, false, this, "I");

			Thread.Sleep(1000);

			this.reset = new GTI.DigitalOutput(this.socket, GT.Socket.Pin.Six, true, this);

			Thread.Sleep(1000);

			this.Reset();

			Thread.Sleep(1000);
			this.device = new GTI.I2CBus(this.socket, TouchC8.I2C_ADDRESS, TouchC8.I2C_CLOCK_RATE, this);

			Thread.Sleep(1000);

			this.interrupt = new GTI.InterruptInput(socket, GT.Socket.Pin.Three, GTI.GlitchFilterMode.Off, GTI.ResistorMode.PullUp, GTI.InterruptMode.FallingEdge, this);
			this.interrupt.Interrupt += new GTI.InterruptInput.InterruptEventHandler(OnInterrupt);

			this.previousWheelDirection = (Direction)(-1);
			this.previousWheelPosition = 0;
			this.previousWheelTouched = false;
			this.previousButton1Touched = false;
			this.previousButton2Touched = false;
			this.previousButton3Touched = false;

			Thread.Sleep(1000);

			this.ConfigureSPM();
		}

		/// <summary>
		/// Gets whether or not the given button is being touched by the user
		/// </summary>
		/// <param name="button">The button to check.</param>
		/// <returns>Whether or not the given button is being touched.</returns>
		public bool IsButtonPressed(Buttons button)
		{
			return (this.ReadRegister(TouchC8.CAP_STAT_LSB) & (byte)button) != 0;
		}

		/// <summary>
		/// Gets whether or not the wheel is being touched by the user.
		/// </summary>
		/// <returns>Whether or not the wheel is being touched.</returns>
		public bool IsWheelPressed()
		{
			return (this.ReadRegister(TouchC8.CAP_STAT_MSB) & 0x10) != 0;
		}

		/// <summary>
		/// Gets whether or not the proximity detector is detecting a nearby object.
		/// </summary>
		/// <returns>Whether or not the sensor is detecting anything.</returns>
		public bool IsProximityDetected()
		{
			return (this.ReadRegister(TouchC8.CAP_STAT_LSB) & 0x1) != 0;
		}

		/// <summary>
		/// Gets the current position of the user on the wheel in degrees.
		/// </summary>
		/// <returns>The degree measure of the user's location on the wheel between 0 and 360.</returns>
		public double GetWheelPosition()
		{
			ushort whlLsb = this.ReadRegister(TouchC8.WHL_POS_LSB);
			ushort whlMsb = this.ReadRegister(TouchC8.WHL_POS_MSB);
			double wheelPosition = (double)((whlMsb << 8) + whlLsb);
			return wheelPosition * (360.0 / (10.0 * TouchC8.WHEELS));
		}

		/// <summary>
		/// Gets the current direction the user is moving on the wheel.
		/// </summary>
		/// <returns>The direction the user is moving.</returns>
		public Direction GetWheelDirection()
		{
			return (this.ReadRegister(TouchC8.CAP_STAT_MSB) & 0x40) != 0 ? Direction.Clockwise : Direction.Counterclockwise;
		}

		private void Reset()
		{
			this.reset.Write(false);
			Thread.Sleep(100);
			this.reset.Write(true);
			Thread.Sleep(100);
		}

		private void OnInterrupt(GTI.InterruptInput sender, bool value)
		{
			byte flags = this.ReadRegister(TouchC8.IRQ_SRC);

			if ((flags & 0x8) != 0)
			{
				double wheelPosition = this.GetWheelPosition();
				bool wheelTouched = this.IsWheelPressed();
				Direction wheelDirection = this.GetWheelDirection();

				if (wheelTouched != this.previousWheelTouched)
					this.OnWheelEvent(this, wheelTouched);

				if (wheelPosition != this.previousWheelPosition || wheelDirection != this.previousWheelDirection)
					this.OnWheelPositionEvent(this, wheelPosition, wheelDirection);

				this.previousWheelTouched = wheelTouched;
				this.previousWheelPosition = wheelPosition;
				this.previousWheelDirection = wheelDirection;
			}

			if ((flags & 0x4) != 0)
			{
				byte cap = this.ReadRegister(TouchC8.CAP_STAT_LSB);
				bool button0 = (cap & 0x1) != 0; //proximity
				bool button1 = (cap & 0x2) != 0;
				bool button2 = (cap & 0x4) != 0;
				bool button3 = (cap & 0x8) != 0;

				if (button0 != this.previousButton0Touched)
					this.OnProximityEvent(this, button0);

				if (button1 != this.previousButton1Touched)
					this.OnButtonEvent(this, Buttons.Up, button1);

				if (button2 != this.previousButton2Touched)
					this.OnButtonEvent(this, Buttons.Middle, button2);

				if (button3 != this.previousButton3Touched)
					this.OnButtonEvent(this, Buttons.Down, button3);

				this.previousButton0Touched = button0;
				this.previousButton1Touched = button1;
				this.previousButton2Touched = button2;
				this.previousButton3Touched = button3;
			}
		}

		private void ConfigureSPM()
		{
			//SPM must be written in 8 byte segments, so that is why we have the extra stuff below.

			//0x4 is cap sensitivity mode, 0xFF to 0x55 are the cap type modes, 0x70 is cap 0 and 1 sensitivty, the last 3 0's set cap 2-7 sensitivity.
			this.WriteSPM(0x9, new byte[] { 0x4, 0xFF, 0xFF, 0x55, 0x70, 0x0, 0x0, 0x0 });

			//0x74 is to enable proximity sensing and the remaining values are the default reserved values that we cannot change
			this.WriteSPM(0x70, new byte[] { 0x74, 0x10, 0x45, 0x2, 0xFF, 0xFF, 0xFF, 0xD5 });
		}

		private void WriteSPM(byte address, byte[] values)
		{
			this.WriteRegister(0x0D, 0x10);
			this.WriteRegister(0x0E, address);

			this.addressBuffer[0] = 0;
			this.device.Write(Utility.CombineArrays(this.addressBuffer, values), 100); //needs to begin with a 0 representing the I2C address of 0.

			this.WriteRegister(0x0D, 0x00);
		}

		private void WriteRegister(byte address, byte value)
		{
			this.writeBuffer[0] = address;
			this.writeBuffer[1] = value;
			this.device.Write(this.writeBuffer, 100);
		}

		private byte ReadRegister(byte address)
		{
			this.addressBuffer[0] = address;
			this.device.WriteRead(this.addressBuffer, this.readBuffer, 100);
			return this.readBuffer[0];
		}
	}
}

#4

@ Jeff - five seconds to instantiate?


#5

Thanks!

I have a Cerbuino NET loaded with the latest FEZ Cerbuino with ethernet firmware. I created a .NET MF 4.2 console application. Added the Touch C8 Code. I get an invalid socket number expection with the following code in Main:

public class Program
    {
        private TouchC8 sensor;

        public static void Main()
        {
            TouchC8 c8 = new TouchC8(2);
            c8.OnButtonPressed +=
                (sender, button, state) =>
                {
                    Debug.Print(button.ToString() + " : " + state.ToString());
                };


        }

I know I’m missing something silly to get this working.


#6

That driver needs a Gadgeteer project to work not just a Console application. Try Gadgeteer project template.