2019-12-03 18:43:54 +01:00
|
|
|
|
using Unosquare.RaspberryIO.Native;
|
|
|
|
|
using Unosquare.Swan.Abstractions;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System;
|
|
|
|
|
|
|
|
|
|
namespace Unosquare.RaspberryIO.Gpio {
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A simple wrapper for the I2c bus on the Raspberry Pi
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class I2CBus : SingletonBase<I2CBus> {
|
|
|
|
|
// TODO: It would be nice to integrate i2c device detection.
|
|
|
|
|
private static readonly Object SyncRoot = new Object();
|
|
|
|
|
private readonly Dictionary<Int32, I2CDevice> _devices = new Dictionary<Int32, I2CDevice>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Prevents a default instance of the <see cref="I2CBus"/> class from being created.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private I2CBus() {
|
|
|
|
|
// placeholder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the registered devices as a read only collection.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ReadOnlyCollection<I2CDevice> Devices => new ReadOnlyCollection<I2CDevice>(this._devices.Values.ToArray());
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the <see cref="I2CDevice"/> with the specified device identifier.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <value>
|
|
|
|
|
/// The <see cref="I2CDevice"/>.
|
|
|
|
|
/// </value>
|
|
|
|
|
/// <param name="deviceId">The device identifier.</param>
|
|
|
|
|
/// <returns>A reference to an I2C device</returns>
|
|
|
|
|
public I2CDevice this[Int32 deviceId] => this.GetDeviceById(deviceId);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the device by identifier.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="deviceId">The device identifier.</param>
|
|
|
|
|
/// <returns>The device reference</returns>
|
|
|
|
|
public I2CDevice GetDeviceById(Int32 deviceId) {
|
|
|
|
|
lock(SyncRoot) {
|
|
|
|
|
return this._devices[deviceId];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Adds a device to the bus by its Id. If the device is already registered it simply returns the existing device.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="deviceId">The device identifier.</param>
|
|
|
|
|
/// <returns>The device reference</returns>
|
|
|
|
|
/// <exception cref="KeyNotFoundException">When the device file descriptor is not found</exception>
|
|
|
|
|
public I2CDevice AddDevice(Int32 deviceId) {
|
|
|
|
|
lock(SyncRoot) {
|
|
|
|
|
if(this._devices.ContainsKey(deviceId)) {
|
|
|
|
|
return this._devices[deviceId];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Int32 fileDescriptor = SetupFileDescriptor(deviceId);
|
|
|
|
|
if(fileDescriptor < 0) {
|
|
|
|
|
throw new KeyNotFoundException($"Device with id {deviceId} could not be registered with the I2C bus. Error Code: {fileDescriptor}.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
I2CDevice device = new I2CDevice(deviceId, fileDescriptor);
|
|
|
|
|
this._devices[deviceId] = device;
|
|
|
|
|
return device;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This initializes the I2C system with your given device identifier.
|
|
|
|
|
/// The ID is the I2C number of the device and you can use the i2cdetect program to find this out.
|
|
|
|
|
/// wiringPiI2CSetup() will work out which revision Raspberry Pi you have and open the appropriate device in /dev.
|
|
|
|
|
/// The return value is the standard Linux filehandle, or -1 if any error – in which case, you can consult errno as usual.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="deviceId">The device identifier.</param>
|
|
|
|
|
/// <returns>The Linux file handle</returns>
|
|
|
|
|
private static Int32 SetupFileDescriptor(Int32 deviceId) {
|
|
|
|
|
lock(SyncRoot) {
|
|
|
|
|
return WiringPi.WiringPiI2CSetup(deviceId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|