2019-12-03 18:43:54 +01:00
|
|
|
|
using System;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Unosquare.RaspberryIO.Native;
|
|
|
|
|
|
|
|
|
|
namespace Unosquare.RaspberryIO.Gpio {
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Represents a device on the I2C Bus
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class I2CDevice {
|
|
|
|
|
private readonly Object _syncLock = new Object();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the <see cref="I2CDevice"/> class.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="deviceId">The device identifier.</param>
|
|
|
|
|
/// <param name="fileDescriptor">The file descriptor.</param>
|
|
|
|
|
internal I2CDevice(Int32 deviceId, Int32 fileDescriptor) {
|
|
|
|
|
this.DeviceId = deviceId;
|
|
|
|
|
this.FileDescriptor = fileDescriptor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the device identifier.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <value>
|
|
|
|
|
/// The device identifier.
|
|
|
|
|
/// </value>
|
|
|
|
|
public Int32 DeviceId {
|
|
|
|
|
get;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the standard POSIX file descriptor.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <value>
|
|
|
|
|
/// The file descriptor.
|
|
|
|
|
/// </value>
|
|
|
|
|
public Int32 FileDescriptor {
|
|
|
|
|
get;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Reads a byte from the specified file descriptor
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The byte from device</returns>
|
|
|
|
|
public Byte Read() {
|
|
|
|
|
lock(this._syncLock) {
|
|
|
|
|
Int32 result = WiringPi.WiringPiI2CRead(this.FileDescriptor);
|
|
|
|
|
if(result < 0) {
|
|
|
|
|
HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (Byte)result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Reads a byte from the specified file descriptor
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The byte from device</returns>
|
|
|
|
|
public Task<Byte> ReadAsync() => Task.Run(() => this.Read());
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Reads a buffer of the specified length, one byte at a time
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="length">The length.</param>
|
|
|
|
|
/// <returns>The byte array from device</returns>
|
|
|
|
|
public Byte[] Read(Int32 length) {
|
|
|
|
|
lock(this._syncLock) {
|
|
|
|
|
Byte[] buffer = new Byte[length];
|
|
|
|
|
for(Int32 i = 0; i < length; i++) {
|
|
|
|
|
Int32 result = WiringPi.WiringPiI2CRead(this.FileDescriptor);
|
|
|
|
|
if(result < 0) {
|
|
|
|
|
HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer[i] = (Byte)result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Reads a buffer of the specified length, one byte at a time
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="length">The length.</param>
|
|
|
|
|
/// <returns>The byte array from device</returns>
|
|
|
|
|
public Task<Byte[]> ReadAsync(Int32 length) => Task.Run(() => this.Read(length));
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Writes a byte of data the specified file descriptor.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">The data.</param>
|
|
|
|
|
public void Write(Byte data) {
|
|
|
|
|
lock(this._syncLock) {
|
|
|
|
|
Int32 result = WiringPi.WiringPiI2CWrite(this.FileDescriptor, data);
|
|
|
|
|
if(result < 0) {
|
|
|
|
|
HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Writes a byte of data the specified file descriptor.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">The data.</param>
|
|
|
|
|
/// <returns>The awaitable task</returns>
|
|
|
|
|
public Task WriteAsync(Byte data) => Task.Run(() => this.Write(data));
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Writes a set of bytes to the specified file descriptor.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">The data.</param>
|
|
|
|
|
public void Write(Byte[] data) {
|
|
|
|
|
lock(this._syncLock) {
|
|
|
|
|
foreach(Byte b in data) {
|
|
|
|
|
Int32 result = WiringPi.WiringPiI2CWrite(this.FileDescriptor, b);
|
|
|
|
|
if(result < 0) {
|
|
|
|
|
HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Writes a set of bytes to the specified file descriptor.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">The data.</param>
|
|
|
|
|
/// <returns>The awaitable task</returns>
|
|
|
|
|
public Task WriteAsync(Byte[] data) => Task.Run(() => this.Write(data));
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// These write an 8 or 16-bit data value into the device register indicated.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The register.</param>
|
|
|
|
|
/// <param name="data">The data.</param>
|
|
|
|
|
public void WriteAddressByte(Int32 address, Byte data) {
|
|
|
|
|
lock(this._syncLock) {
|
|
|
|
|
Int32 result = WiringPi.WiringPiI2CWriteReg8(this.FileDescriptor, address, data);
|
|
|
|
|
if(result < 0) {
|
|
|
|
|
HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressByte));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// These write an 8 or 16-bit data value into the device register indicated.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The register.</param>
|
|
|
|
|
/// <param name="data">The data.</param>
|
|
|
|
|
public void WriteAddressWord(Int32 address, UInt16 data) {
|
|
|
|
|
lock(this._syncLock) {
|
|
|
|
|
Int32 result = WiringPi.WiringPiI2CWriteReg16(this.FileDescriptor, address, data);
|
|
|
|
|
if(result < 0) {
|
|
|
|
|
HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressWord));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// These read an 8 or 16-bit value from the device register indicated.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The register.</param>
|
|
|
|
|
/// <returns>The address byte from device</returns>
|
|
|
|
|
public Byte ReadAddressByte(Int32 address) {
|
|
|
|
|
lock(this._syncLock) {
|
|
|
|
|
Int32 result = WiringPi.WiringPiI2CReadReg8(this.FileDescriptor, address);
|
|
|
|
|
if(result < 0) {
|
|
|
|
|
HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressByte));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (Byte)result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// These read an 8 or 16-bit value from the device register indicated.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="address">The register.</param>
|
|
|
|
|
/// <returns>The address word from device</returns>
|
|
|
|
|
public UInt16 ReadAddressWord(Int32 address) {
|
|
|
|
|
lock(this._syncLock) {
|
|
|
|
|
Int32 result = WiringPi.WiringPiI2CReadReg16(this.FileDescriptor, address);
|
|
|
|
|
if(result < 0) {
|
|
|
|
|
HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressWord));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Convert.ToUInt16(result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|