David's Random Projects and Documents
Feel free to use and link to any docs you find here. Please give credit and link back to this page on any publicly avaliable copies.

C# IO Library for the Intel Edison Arduino Board

I've recently been blinking LEDs for a video tracking project and thought I'd share my IO library for the Edison Arduino board. At this point in time only pins D03, D05, D06, D09 and D10 have been implemented and tested. If you need other pins initialization is handled in the IOSet() constructor. Every new IO must be added to the pins dictionary with a Pin enumeration (you'll have to add an enumeration constant here too) and new ArdGPIO(...). The ArdGPIO constructor takes low level intel edison pins controlling pull-up/down, direction, and value states respectively and has an optional Action parameter for special initialization procedures such as are required for PWM pins (see D10 initialization). Pin connection diagrams can be found in this document which was taken from a post on the Edison Forum (can't find the link right now...).

Usage

Getting an IO pin handle

using Edison.IO;
...
ArdGPIO pin3 = ArdIO.GPIO[ArdGPIO.Pin.D03];
...

Pin Modes

//Output - Output value written to pin.Value
pin3.IODirection = ArdGPIO.Direction.Out;
pin3.IOValue = ArdIO.Value.High; //Physical pin D03 should be outputting a High state signal
pin3.IOValue = ArdIO.Value.Low; //Physical pin D03 should be outputting a Low state signal

//Input - Set pin to High-Z state. values can be read from pin.Value
pin3.IODirection = ArdGPIO.Direction.In;
ArdIO.Value value = pin3.IOValue; //value will contain the digital state read from Pyisical pin D03

//High - Set pin to input state with pull-up resistor enabled. values can be read from pin.Value
pin3.IODirection = ArdGPIO.Direction.High;
ArdIO.Value value = pin3.IOValue; //value will contain the digital state read from Pyisical pin D03, High if no connection

//Low - Set pin to input state with pull-down resistor enabled. values can be read from pin.Value
pin3.IODirection = ArdGPIO.Direction.Low;
ArdIO.Value value = pin3.IOValue; //value will contain the digital state read from Pyisical pin D03, Low if no connection

Source

using System;
using System.Collections.Generic;

namespace Edison.IO
{
    class ArdGPIO
    {
        private static void ExportIO(int io)
        {
            using (System.IO.StreamWriter sw = new System.IO.StreamWriter("/sys/class/gpio/export"))
            {
                sw.Write(io.ToString());
            }
        }

        private static bool IsIOExported(int io)
        {
            return System.IO.Directory.Exists("/sys/class/gpio/gpio" + io.ToString());
        }

        private static void SetMux(int pin, int mode)
        {
            using (System.IO.StreamWriter sw = 
                new System.IO.StreamWriter("/sys/kernel/debug/gpio_debug/gpio" +
                    pin.ToString() + "/current_pinmux"))
            {
                sw.Write("mode" + mode.ToString());
            }
        }

        private static void SetDirection(int pin, Direction dir)
        {
            using (System.IO.StreamWriter sw = 
                new System.IO.StreamWriter("/sys/class/gpio/gpio" + pin.ToString() + "/direction"))
            {
                switch (dir)
                {
                    case Direction.High:
                        sw.Write("high");
                        break;
                    case Direction.Low:
                        sw.Write("low");
                        break;
                    case Direction.In:
                        sw.Write("in");
                        break;
                    case Direction.Out:
                        sw.Write("out");
                        break;
                }
            }
        }

        private static Direction GetDirection(int pin)
        {
            using (System.IO.StreamReader sr =
                new System.IO.StreamReader("/sys/class/gpio/gpio" + pin.ToString() + "/direction"))
            {
                string val = sr.ReadToEnd().Trim().ToLower();
                if (val == "high")
                    return Direction.High;
                else if (val == "low")
                    return Direction.Low;
                else if (val == "in")
                    return Direction.In;
                else if (val == "out")
                    return Direction.Out;
            }
            throw new FormatException("Unrecognized Response");
        }

        private static void SetValue(int pin, Value value)
        {
            using (System.IO.StreamWriter sw =
                new System.IO.StreamWriter("/sys/class/gpio/gpio" + pin.ToString() + "/value"))
            {
                switch (value)
                {
                    case Value.High:
                        sw.Write("1");
                        break;
                    case Value.Low:
                        sw.Write("0");
                        break;
                }
            }
        }

        private static Value GetValue(int pin)
        {
            using (System.IO.StreamReader sr =
                new System.IO.StreamReader("/sys/class/gpio/gpio" + pin.ToString() + "/value"))
            {
                string val = sr.ReadToEnd().Trim();
                if (val == "0")
                    return Value.Low;
                else if (val == "1")
                    return Value.High;
            }
            throw new FormatException("Unrecognized Response");
        }

        public enum Pin
        {
            D03, D05, D06, D09, D10
        }

        public enum Direction
        {
            In, Out, High, Low
        }

        public enum Value
        {
            High, Low
        }

        public class IOSet
        {
            internal static bool isInitialized
            {
                get
                {
                    return ArdGPIO.IsIOExported(214);
                }
            }

            internal static void Initialize()
            {
                ArdGPIO.ExportIO(214);
                ArdGPIO.SetDirection(214, Direction.High);
            }

            private Dictionary<Pin, ArdGPIO> pins = new Dictionary<Pin,ArdGPIO>();

            public ArdGPIO this[Pin pin]
            {
                get { return this.pins[pin]; }
            }

            public IOSet()
            {
                this.pins.Add(Pin.D03, new ArdGPIO(219, 251, 12));
                this.pins.Add(Pin.D05, new ArdGPIO(221, 253, 13));
                this.pins.Add(Pin.D06, new ArdGPIO(222, 254, 182));
                this.pins.Add(Pin.D09, new ArdGPIO(225, 257, 183));
                this.pins.Add(Pin.D10, new ArdGPIO(226, 258, 41, () =>
                {
                    if (!IsIOExported(240))
                        ExportIO(240);
                    SetDirection(240, Direction.Out);
                    SetValue(240, Value.Low);

                    if (!IsIOExported(263))
                        ExportIO(263);
                    SetDirection(263, Direction.Out);
                    SetValue(263, Value.High);
                }));
            }
        }

        private static IOSet gpios = new IOSet();

        public static IOSet GPIO
        {
            get { return gpios; }
        }

        private int PullUD_Pin;
        private int Direction_Pin;
        private int IO_Pin;
        private bool init = false;

        public Direction IODirection
        {
            set
            {
                this.InitilizeIfRequired();
                switch (value)
                {
                    case Direction.High:
                        ArdGPIO.SetDirection(this.IO_Pin, Direction.High);
                        ArdGPIO.SetValue(this.PullUD_Pin, Value.High);
                        ArdGPIO.SetDirection(this.PullUD_Pin, Direction.Out);
                        ArdGPIO.SetValue(this.Direction_Pin, Value.Low);
                        ArdGPIO.SetDirection(this.IO_Pin, Direction.In);
                        break;
                    case Direction.Low:
                        ArdGPIO.SetDirection(this.IO_Pin, Direction.Low);
                        ArdGPIO.SetValue(this.PullUD_Pin, Value.Low);
                        ArdGPIO.SetDirection(this.PullUD_Pin, Direction.Out);
                        ArdGPIO.SetValue(this.Direction_Pin, Value.Low);
                        ArdGPIO.SetDirection(this.IO_Pin, Direction.In);
                        break;
                    case Direction.In:
                        ArdGPIO.SetDirection(this.IO_Pin, Direction.Low);
                        ArdGPIO.SetDirection(this.PullUD_Pin, Direction.In);
                        ArdGPIO.SetValue(this.Direction_Pin, Value.Low);
                        ArdGPIO.SetDirection(this.IO_Pin, Direction.In);
                        break;
                    case Direction.Out:
                        var val = ArdGPIO.GetValue(this.IO_Pin);
                        ArdGPIO.SetDirection(this.IO_Pin, val == Value.High ? Direction.High : Direction.Low);
                        ArdGPIO.SetDirection(this.PullUD_Pin, Direction.In);
                        ArdGPIO.SetValue(this.Direction_Pin, Value.High);
                        ArdGPIO.SetDirection(this.IO_Pin, Direction.Out);
                        break;
                }
            }
            get
            {
                this.InitilizeIfRequired();
                var dirVal = ArdGPIO.GetValue(this.Direction_Pin);
                if (dirVal == Value.High)
                    return Direction.Out;
                else
                {
                    var puDir = ArdGPIO.GetDirection(this.PullUD_Pin);
                    if (puDir == Direction.In)
                        return Direction.In;
                    else
                    {
                        if (ArdGPIO.GetValue(this.PullUD_Pin) == Value.High)
                            return Direction.High;
                        else
                            return Direction.Low;
                    }
                }
            }
        }

        public Value IOValue
        {
            get
            {
                this.InitilizeIfRequired();
                return ArdGPIO.GetValue(this.IO_Pin);
            }
            set
            {
                this.InitilizeIfRequired();
                ArdGPIO.SetValue(this.IO_Pin, value);
            }
        }

        public ArdGPIO(int PullUD_Pin, int Direction_Pin, int IO_Pin, Action preInit = null)
        {
            if (preInit != null)
                preInit();
            this.PullUD_Pin = PullUD_Pin;
            this.Direction_Pin = Direction_Pin;
            this.IO_Pin = IO_Pin;
        }

        private void InitilizeIfRequired()
        {
            if (this.init)
                return;
            this.init = true;
            if (!IOSet.isInitialized)
                IOSet.Initialize();
            if (!ArdGPIO.IsIOExported(this.IO_Pin))
                ArdGPIO.ExportIO(this.IO_Pin);
            if (!ArdGPIO.IsIOExported(this.Direction_Pin))
                ArdGPIO.ExportIO(this.Direction_Pin);
            if (!ArdGPIO.IsIOExported(this.PullUD_Pin))
                ArdGPIO.ExportIO(this.PullUD_Pin);

            ArdGPIO.SetMux(this.IO_Pin, 0);
            ArdGPIO.SetDirection(this.IO_Pin, Direction.High);
            ArdGPIO.SetDirection(this.Direction_Pin, Direction.Low);
            ArdGPIO.SetDirection(this.PullUD_Pin, Direction.Low);
            ArdGPIO.SetValue(this.Direction_Pin, Value.Low);
            ArdGPIO.SetDirection(this.Direction_Pin, Direction.Out);
            ArdGPIO.SetValue(this.PullUD_Pin, Value.Low);
            ArdGPIO.SetDirection(this.IO_Pin, Direction.In);
        }
    }
}