// 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 IO.Interfaces.Message64; namespace IO.Objects.RemoteIO { public partial class Device { /// /// Query available I2C buses. /// /// List of available I2C bus numbers. public System.Collections.Generic.List I2C_Available() { return Available(PeripheralTypes.I2C); } /// /// Create a remote I2C bus controller. /// /// I2C bus number: 0 to 127. /// I2C bus clock frequency in Hz /// I2C bus controller object. public IO.Interfaces.I2C.Bus I2C_Create(int num, int speed = IO.Interfaces.I2C.Speeds.StandardMode) { return new I2C(this, num, speed); } } /// /// Encapsulates remote I2C buses. /// public class I2C : IO.Interfaces.I2C.Bus { private readonly Device device; private readonly int num; /// /// Create a remote I2C bus controller. /// /// Remote I/O device object. /// I2C bus number: 0 to 127. /// I2C bus clock frequency in Hz /// Use Device.I2C_Create() instead of this constructor. public I2C(Device dev, int num, int speed = IO.Interfaces.I2C.Speeds.StandardMode) { this.device = dev; this.num = (byte)num; // Validate parameters if ((num < 0) || (num >= Device.MAX_CHANNELS)) throw new Exception("Invalid I2C bus number"); if ((speed < 0) || (speed > IO.Interfaces.I2C.Speeds.FastModePlus)) throw new Exception("Invalid I2C bus speed"); Message cmd = new Message(0); Message resp = new Message(); cmd.payload[0] = (byte)MessageTypes.I2C_CONFIGURE_REQUEST; cmd.payload[2] = (byte)num; cmd.payload[3] = (byte)((speed >> 24) & 0xFF); cmd.payload[4] = (byte)((speed >> 16) & 0xFF); cmd.payload[5] = (byte)((speed >> 8) & 0xFF); cmd.payload[6] = (byte)(speed & 0xFF); device.Dispatcher(cmd, resp); } /// /// Read bytes from an I2C slave device. /// /// I2C slave address. /// Response buffer. /// Number of bytes to read. public void Read(int slaveaddr, byte[] resp, int resplen) { // Validate parameters if ((slaveaddr < 0) || (slaveaddr > 127)) throw new Exception("Invalid I2C slave address"); if ((resplen < 1) || (resplen > 60) || (resp.Length < resplen)) throw new Exception("Invalid response length"); Message cmsg = new Message(0); Message rmsg = new Message(); cmsg.payload[0] = (byte)MessageTypes.I2C_TRANSACTION_REQUEST; cmsg.payload[2] = (byte)this.num; cmsg.payload[3] = (byte)slaveaddr; cmsg.payload[5] = (byte)resplen; this.device.Dispatcher(cmsg, rmsg); for (int i = 0; i < resplen; i++) resp[i] = rmsg.payload[i + 4]; } /// /// Write bytes to an I2C slave device. /// /// I2C slave address. /// Command buffer. /// Number of bytes to write. public void Write(int slaveaddr, byte[] cmd, int cmdlen) { // Validate parameters if ((slaveaddr < 0) || (slaveaddr > 127)) throw new Exception("Invalid I2C slave address"); if ((cmdlen < 1) || (cmdlen > 56) || (cmd.Length < cmdlen)) throw new Exception("Invalid command length"); Message cmsg = new Message(0); Message rmsg = new Message(); for (int i = 0; i < cmdlen; i++) cmsg.payload[8 + i] = cmd[i]; cmsg.payload[0] = (byte)MessageTypes.I2C_TRANSACTION_REQUEST; cmsg.payload[2] = (byte)this.num; cmsg.payload[3] = (byte)slaveaddr; cmsg.payload[4] = (byte)cmdlen; this.device.Dispatcher(cmsg, rmsg); } /// /// Write and read bytes to and from an I2C slave device. /// /// I2C slave address. /// Command buffer. /// Number of bytes to write. /// Response buffer. /// Number of bytes to read. /// Delay in microseconds between the I2C /// write and read cycles. Allowed values are 0 to 65535 microseconds. public void Transaction(int slaveaddr, byte[] cmd, int cmdlen, byte[] resp, int resplen, int delayus) { // Validate parameters if ((slaveaddr < 0) || (slaveaddr > 127)) throw new Exception("Invalid I2C slave address parameter"); if ((cmd == null) && (resp == null)) throw new Exception("Command buffer and response buffer are both null"); if ((cmdlen == 0) && (resplen == 0)) throw new Exception("Command length and response length are both zero"); if ((cmd == null) && (cmdlen != 0)) throw new Exception("Command buffer is null but command length is nonzero"); if ((cmd != null) && (cmdlen == 0)) throw new Exception("Command buffer is not null but command length is zero"); if ((resp == null) && (resplen != 0)) throw new Exception("Response buffer is null but response length is nonzero"); if ((resp != null) && (resplen == 0)) throw new Exception("Response buffer is not null but response length is zero"); if (cmd != null) if ((cmdlen < 1) || (cmdlen > 56) || (cmd.Length < cmdlen)) throw new Exception("Invalid command length parameter"); if (resp != null) if ((resplen < 1) || (resplen > 60) || (resp.Length < resplen)) throw new Exception("Invalid response length parameter"); if ((delayus < 0) || (delayus > 65535)) throw new Exception("Invalid delay parameter"); Message cmsg = new Message(0); Message rmsg = new Message(); cmsg.payload[0] = (byte)MessageTypes.I2C_TRANSACTION_REQUEST; cmsg.payload[2] = (byte)this.num; cmsg.payload[3] = (byte)slaveaddr; cmsg.payload[4] = (byte)cmdlen; cmsg.payload[5] = (byte)resplen; cmsg.payload[6] = (byte)(delayus / 256); cmsg.payload[7] = (byte)(delayus % 256); for (int i = 0; i < cmdlen; i++) cmsg.payload[8 + i] = cmd[i]; this.device.Dispatcher(cmsg, rmsg); for (int i = 0; i < resplen; i++) resp[i] = rmsg.payload[4 + i]; } } }