// GPIO pin services using IO.Objects.SimpleIO // Copyright (C)2017-2023, Philip Munts dba Munts Technologies. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. using System; namespace IO.Objects.SimpleIO.GPIO { /// /// GPIO output driver settings. /// public enum Driver { /// /// Push Pull (current source/sink) output driver. /// PushPull, /// /// Open Drain (current sink) output driver. /// OpenDrain, /// /// Open Source (current source) output driver. /// OpenSource }; /// /// GPIO input interrupt edge settings. /// public enum Edge { /// /// Configure GPIO input pin with interrupt disabled. /// None, /// /// Configure GPIO input pin to interrupt on rising edge. /// Rising, /// /// Configure GPIO pin to interrupt on falling edge. /// Falling, /// /// Configure GPIO pin to interrupt on both edges. /// Both }; /// /// GPIO polarity settings /// public enum Polarity { /// /// Configure GPIO pin as active low (inverted logic). /// ActiveLow, /// /// Configure GPIO pin as active high (normal logic). /// ActiveHigh }; /// /// Encapsulates Linux GPIO pins using libsimpleio. /// public class Pin : IO.Interfaces.GPIO.Pin { private readonly int myfd; private readonly Kinds kind; private enum Kinds { Input, Output, Interrupt }; private void CalculateFlags(IO.Interfaces.GPIO.Direction dir, Driver driver, Edge edge, Polarity polarity, out int flags, out int events, out Kinds kind) { flags = 0; events = 0; kind = Kinds.Input; // Validate parameters if ((dir < IO.Interfaces.GPIO.Direction.Input) || (dir > IO.Interfaces.GPIO.Direction.Output)) { throw new Exception("Invalid direction parameter"); } if ((driver < Driver.PushPull) || (driver > Driver.OpenSource)) { throw new Exception("Invalid driver parameter"); } if ((edge < Edge.None) || (edge > Edge.Both)) { throw new Exception("Invalid edge parameter"); } if ((polarity < Polarity.ActiveLow) || (polarity > Polarity.ActiveHigh)) { throw new Exception("Invalid polarity parameter"); } // Set flags for the GPIO pin data direction switch (dir) { case IO.Interfaces.GPIO.Direction.Input: flags |= IO.Bindings.libsimpleio.GPIO_LINE_REQUEST_INPUT; break; case IO.Interfaces.GPIO.Direction.Output: flags |= IO.Bindings.libsimpleio.GPIO_LINE_REQUEST_OUTPUT; break; } // Set flags for the GPIO pin output driver switch (driver) { case Driver.PushPull: flags |= IO.Bindings.libsimpleio.GPIO_LINE_REQUEST_PUSH_PULL; break; case Driver.OpenDrain: flags |= IO.Bindings.libsimpleio.GPIO_LINE_REQUEST_OPEN_DRAIN; break; case Driver.OpenSource: flags |= IO.Bindings.libsimpleio.GPIO_LINE_REQUEST_OPEN_SOURCE; break; } // Set flags for the GPIO pin polarity switch (polarity) { case Polarity.ActiveLow: flags |= IO.Bindings.libsimpleio.GPIO_LINE_REQUEST_ACTIVE_LOW; break; case Polarity.ActiveHigh: flags |= IO.Bindings.libsimpleio.GPIO_LINE_REQUEST_ACTIVE_HIGH; break; } // Set flags for the GPIO pin input interrupt trigger edge(s) switch (edge) { case Edge.None: events |= IO.Bindings.libsimpleio.GPIO_EVENT_REQUEST_NONE; break; case Edge.Rising: events |= IO.Bindings.libsimpleio.GPIO_EVENT_REQUEST_RISING; break; case Edge.Falling: events |= IO.Bindings.libsimpleio.GPIO_EVENT_REQUEST_FALLING; break; case Edge.Both: events |= IO.Bindings.libsimpleio.GPIO_EVENT_REQUEST_BOTH; break; } if (dir == Interfaces.GPIO.Direction.Output) kind = Kinds.Output; else if (edge != Edge.None) kind = Kinds.Interrupt; else kind = Kinds.Input; } /// /// Constructor for a single GPIO pin. /// /// GPIO pin designator. /// Data direction. /// Initial GPIO output state. /// Output driver setting. /// Interrupt edge setting. /// Polarity setting. public Pin(IO.Objects.SimpleIO.Device.Designator desg, IO.Interfaces.GPIO.Direction dir, bool state = false, Driver driver = Driver.PushPull, Edge edge = Edge.None, Polarity polarity = Polarity.ActiveHigh) { // Validate the GPIO pin designator if ((desg.chip == IO.Objects.SimpleIO.Device.Designator.Unavailable.chip) || (desg.chan == IO.Objects.SimpleIO.Device.Designator.Unavailable.chan)) { throw new Exception("Invalid designator"); } CalculateFlags(dir, driver, edge, polarity, out int flags, out int events, out this.kind); IO.Bindings.libsimpleio.GPIO_line_open((int)desg.chip, (int)desg.chan, flags, events, state ? 1 : 0, out this.myfd, out int error); if (error != 0) { throw new Exception("GPIO_line_open() failed, " + errno.strerror(error)); } } /// /// Read/Write GPIO state property. /// public bool state { get { int error; int value = 0; switch (this.kind) { case Kinds.Input: case Kinds.Output: IO.Bindings.libsimpleio.GPIO_line_read(this.myfd, out value, out error); if (error != 0) { throw new Exception("GPIO_line_read() failed, " + errno.strerror(error)); } break; case Kinds.Interrupt: IO.Bindings.libsimpleio.GPIO_line_event(this.myfd, out value, out error); if (error != 0) { throw new Exception("GPIO_line_event() failed, " + errno.strerror(error)); } break; } return value != 0; } set { int error; switch (this.kind) { case Kinds.Input: case Kinds.Interrupt: throw new Exception("Cannot write to input pin"); case Kinds.Output: IO.Bindings.libsimpleio.GPIO_line_write(this.myfd, value ? 1 : 0, out error); if (error != 0) { throw new Exception("GPIO_line_write() failed, " + errno.strerror(error)); } break; } } } /// /// Read-only property returning the Linux file descriptor for the /// GPIO pin. /// public int fd { get { return this.myfd; } } } }