// 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; using System.Collections.Generic; using IO.Interfaces.Message64; namespace IO.Objects.RemoteIO { /// /// Types of remote peripherals /// public enum PeripheralTypes { /// /// A/D inputs /// ADC, /// /// D/A outputs /// DAC, /// /// GPIO pins /// GPIO, /// /// I2C bus controllers /// I2C, /// /// SPI slave devices /// PWM, /// /// PWM outputs /// SPI, } /// /// Encasulates a Remote I/O Protocol server device. /// public partial class Device { private readonly Messenger transport; private readonly String Version_string; private readonly String Capability_string; private byte msgnum = 0; /// /// Maximum number of channels each subsystem can support. /// public const int MAX_CHANNELS = 128; /// /// Designator for an unavailable channel. /// public const int Unavailable = -1; // Fetch version string private string FetchVersion() { Message cmd = new Message(0); Message resp = new Message(); cmd.payload[0] = (byte)MessageTypes.VERSION_REQUEST; cmd.payload[1] = 1; this.transport.Transaction(cmd, resp); return System.Text.Encoding.UTF8.GetString(resp.payload, 3, Message.Size - 3).Trim('\0'); } // Fetch capability string private string FetchCapabilities() { Message cmd = new Message(0); Message resp = new Message(); cmd.payload[0] = (byte)MessageTypes.CAPABILITY_REQUEST; cmd.payload[1] = 2; this.transport.Transaction(cmd, resp); return System.Text.Encoding.UTF8.GetString(resp.payload, 3, Message.Size - 3).Trim('\0'); } /// /// Create a Remote I/O server device object using a Messenger transport object. /// /// Messenger transport object. public Device(Messenger m) { transport = m; Version_string = FetchVersion(); Capability_string = FetchCapabilities(); } /// /// Create a Remote I/O server device object using UDP transport. /// /// UDP server domain name or IP address. /// UDP server port number. /// Receive timeout in milliseconds. Zero /// indicates wait forever. public Device(string host, int port = 8087, int timeoutms = 1000) { transport = new IO.Objects.Message64.UDP.Messenger(host, port, timeoutms); Version_string = FetchVersion(); Capability_string = FetchCapabilities(); } /// /// Command dispatcher. /// /// Command to be sent. /// Response to be received. public void Dispatcher(Message cmd, Message resp) { unchecked { msgnum += 17; } cmd.payload[1] = msgnum; this.transport.Transaction(cmd, resp); if (resp.payload[0] != cmd.payload[0] + 1) throw new Exception("Invalid response message type"); if (resp.payload[1] != cmd.payload[1]) throw new Exception("Invalid response message number"); if (resp.payload[2] != 0) throw new Exception("Command failed, error=" + resp.payload[2].ToString()); } /// /// Version string from the Remote I/O device. /// public String Version { get { return this.Version_string; } } /// /// Capability string from the Remote I/O device. /// public String Capabilities { get { return this.Capability_string; } } private static readonly string[] CapStrings = new string[] { "ADC", "DAC", "GPIO", "I2C", "PWM", "SPI", }; private static readonly MessageTypes[] MsgTypes = new MessageTypes[] { MessageTypes.ADC_PRESENT_REQUEST, MessageTypes.DAC_PRESENT_REQUEST, MessageTypes.GPIO_PRESENT_REQUEST, MessageTypes.I2C_PRESENT_REQUEST, MessageTypes.PWM_PRESENT_REQUEST, MessageTypes.SPI_PRESENT_REQUEST, }; private List Available(PeripheralTypes t) { List peripherals = new List(MAX_CHANNELS); // Check whether the Remote I/O device supports this peripheral type if (this.Capabilities == String.Empty) return peripherals; if (this.Capabilities.IndexOf(CapStrings[(int)t]) < 0) return peripherals; // Query available peripherals Message cmd = new Message(0); Message resp = new Message(); cmd.payload[0] = (byte)MsgTypes[(int)t]; cmd.payload[1] = 5; this.transport.Transaction(cmd, resp); // Build the list of available peripherals for (int num = 0; num < MAX_CHANNELS; num++) { int bytenum = num / 8; byte bitmask = (byte)(1 << (7 - num % 8)); if ((resp.payload[3 + bytenum] & bitmask) != 0) peripherals.Add(num); } // Return the list of available peripherals return peripherals; } } }