// 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;
}
}
}