How to use Gadgeteer Interfaces directly from your application

One of the benefits of the .NET Gadgeteer design is that it provides ready-to-use hardware modules. Module designers can build libraries in such a way that they take care of the lower-level communication protocols and electrical signals that need to take place between the mainboard and the modules. Users of those modules can simply connect the hardware together, and use the high-level programming interfaces provided by the libraries.

At the same time, .NET Gadgeteer is just as much about extensibility as it is about ease of use. To this end, the Gadgeteer.Interfaces namespace provides direct access to the most commonly used communication and electrical input/output capabilities of the mainboard. Interfaces are not usually accessed directly from a Gadgeteer application, and are more regularly used inside module libraries as a way to control or communicate with the module hardware. For example, a module library might internally use a DigitalInput interface to monitor the state of a button, a DigitalOutput to control an LED, or an I2CBus to read the value of a sensor.

The interfaces currently supported are: AnalogInput, AnalogOutput, DigitalInput, DigitalIO, DigitalOutput, I2CBus, InterruptInput, PWMOutput, Serial and SPI.

Interfaces are closely related to the concept of socket types, in that different socket types support different interfaces. For example, socket type I specifies the electrical pinout for the I2CBus interface (SDA and SCL, on pins 8 and 9). However, there is not a one-to-one mapping between socket types and interfaces. For instance, the same socket type I definition specifies that in any mainboard socket labelled with an I, both pins 3 and 6 are GPIOs. These pins can be controlled by using any of the DigitalInput, DigitalOutput or DigitalIO interfaces. In addition, pin 3 is marked as being interrupt-capable, and these capabilities can be accessed by using the InterrruptInput interface. 

Using Gadgeteer.Interfaces from an Application

As mentioned, interfaces are most often used from within module libraries. I highly recommend reading this blog post, written by Pete Brown about the process of creating a new hardware module, and writing the accompanying software library for it.

 

There are also cases when it is useful to be able to use the interfaces directly from the application code. For example, you might want to quickly test a new sensor without the overhead of creating a new module library. Here's how you do that:

As a first step, it is good practice to add the following line of code to the using-statement block, at the top of the application code file:

 

 

using GTI = Gadgeteer.Interfaces;

 

 

This is optional, but it allows GTI to be used as a shortcut to the Gadgeteer.Interfaces namespace throughout the code, in the same way that GT is used as a shortcut for Gadgeteer, and GTM for Gadgeteer.Modules.

 

In order to initialize any interface, it is necessary to specify the mainboard socket through which the interface will be used. It is possible to get a reference to any of the mainboard sockets by using a statement like this:

 

 

GT.Socket socket = GT.Socket.GetSocket(4, true, null, null);

 
 

In this case, the GetSocket method returns a reference to the mainboard socket number 4. The second parameter specifies that an exception will be thrown if the socket number is invalid (i.e.. if the mainboard didn't actually have a socket number 4). The third and fourth parameters can be null, since they are only applicable when the interface is being used from within a module library.

 

The following code snippet is an example of a I2CBus interface being defined, initialized within ProgramStarted(), and then used from a method called Test():

 

public partial class Program
{

GTI.I2CBus i2c;

void ProgramStarted()
{

GT.Socket socket = GT.Socket.GetSocket(4, true, null, null);
i2c = new GTI.I2CBus(socket, 0x11, 50, null);
Test();

}

void Test()
{

byte[] buffer = new byte[]{0x01, 0x02, 0x03};
i2c.Write(buffer, 100);

}

}