Skip to content

Commit

Permalink
Add I2cTransferResult and I2cTransferStatus (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
josesimoes authored Oct 27, 2020
1 parent b388ba4 commit 96aab04
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 47 deletions.
134 changes: 93 additions & 41 deletions System.Device.I2c/I2cDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.CompilerServices;

namespace System.Device.I2c
{
Expand All @@ -11,25 +11,40 @@ namespace System.Device.I2c
/// </summary>
public class I2cDevice : IDisposable
{
// this is used as the lock object
// a lock is required because multiple threads can access the device
[Diagnostics.DebuggerBrowsable(Diagnostics.DebuggerBrowsableState.Never)]
private readonly object _syncLock;

private Windows.Devices.I2c.I2cDevice _device;
// For the ReadByte and WriteByte operations
private byte[] bufferSingleOperation = new byte[1];
[Diagnostics.DebuggerBrowsable(Diagnostics.DebuggerBrowsableState.Never)]
private readonly I2cConnectionSettings _connectionSettings;

[Diagnostics.DebuggerBrowsable(Diagnostics.DebuggerBrowsableState.Never)]
private bool _disposed;

// speeds up the execution of ReadByte and WriteByte operations
private readonly byte[] _buffer;

/// <summary>
/// The connection settings of a device on an I2C bus. The connection settings are immutable after the device is created
/// so the object returned will be a clone of the settings object.
/// </summary>
public I2cConnectionSettings ConnectionSettings { get; }
public I2cConnectionSettings ConnectionSettings { get => _connectionSettings; }

/// <summary>
/// Reads a byte from the I2C device.
/// </summary>
/// <returns>A byte read from the I2C device.</returns>
public byte ReadByte()
{
_device.Read(bufferSingleOperation);
return bufferSingleOperation[0];
lock (_syncLock)
{
var buffer = new SpanByte(_buffer);

NativeTransmit(null, buffer);

return buffer[0];
}
}

/// <summary>
Expand All @@ -39,26 +54,27 @@ public byte ReadByte()
/// The buffer to read the data from the I2C device.
/// The length of the buffer determines how much data to read from the I2C device.
/// </param>
public void Read(SpanByte buffer)
public I2cTransferResult Read(SpanByte buffer)
{
// This is allocating an intermediate buffer and then copy back the data to
// the SpanByte. This is intend to be changed in a native implementation
byte[] toRead = new byte[buffer.Length];
_device.Read(toRead);
for (int i = 0; i < toRead.Length; i++)
lock (_syncLock)
{
buffer[i] = toRead[i];
return NativeTransmit(null, buffer);
}
}

/// <summary>
/// Writes a byte to the I2C device.
/// </summary>
/// <param name="value">The byte to be written to the I2C device.</param>
public void WriteByte(byte value)
public I2cTransferResult WriteByte(byte value)
{
bufferSingleOperation[0] = value;
_device.Write(bufferSingleOperation);
lock (_syncLock)
{
// copy value
_buffer[0] = value;

return NativeTransmit(new SpanByte(_buffer), null);
}
}

/// <summary>
Expand All @@ -68,11 +84,12 @@ public void WriteByte(byte value)
/// The buffer that contains the data to be written to the I2C device.
/// The data should not include the I2C device address.
/// </param>
public void Write(SpanByte buffer)
public I2cTransferResult Write(SpanByte buffer)
{
// This is allocating an intermediate buffer using the buffer of
// the SpanByte. This is intend to be changed in a native implementation
_device.Write(buffer.ToArray());
lock (_syncLock)
{
return NativeTransmit(buffer, null);
}
}

/// <summary>
Expand All @@ -86,15 +103,11 @@ public void Write(SpanByte buffer)
/// The buffer to read the data from the I2C device.
/// The length of the buffer determines how much data to read from the I2C device.
/// </param>
public void WriteRead(SpanByte writeBuffer, SpanByte readBuffer)
public I2cTransferResult WriteRead(SpanByte writeBuffer, SpanByte readBuffer)
{
// This is allocating an intermediate buffer and then copy back the data to
// the SpanByte. This is intend to be changed in a native implementation
byte[] toRead = new byte[readBuffer.Length];
_device.WriteRead(writeBuffer.ToArray(), toRead);
for (int i = 0; i < toRead.Length; i++)
lock (_syncLock)
{
readBuffer[i] = toRead[i];
return NativeTransmit(writeBuffer, readBuffer);
}
}

Expand All @@ -114,26 +127,65 @@ public static I2cDevice Create(I2cConnectionSettings settings)
/// <param name="settings">Connection settings</param>
public I2cDevice(I2cConnectionSettings settings)
{
ConnectionSettings = settings;
_device = Windows.Devices.I2c.I2cDevice.FromId($"I2C{settings.BusId}", new Windows.Devices.I2c.I2cConnectionSettings(settings.DeviceAddress)
_connectionSettings = settings;

// create the buffer
_buffer = new byte[1];

// create the lock object
_syncLock = new object();

// call native init to allow HAL/PAL inits related with I2C hardware
NativeInit();
}

#region IDisposable Support

private void Dispose(bool disposing)
{
if (!_disposed)
{
BusSpeed = (Windows.Devices.I2c.I2cBusSpeed)settings.BusSpeed,
SharingMode = (Windows.Devices.I2c.I2cSharingMode)settings.SharingMode
});
NativeDispose();

_disposed = true;
}
}

/// <inheritdoc cref="IDisposable.Dispose"/>
public void Dispose()
#pragma warning disable 1591
~I2cDevice()
{
Dispose(true);
GC.SuppressFinalize(this);
Dispose(false);
}

/// <summary>
/// Disposes this instance
/// <inheritdoc cref="IDisposable.Dispose"/>
/// </summary>
/// <param name="disposing"><see langword="true"/> if explicitly disposing, <see langword="false"/> if in finalizer</param>
void Dispose(bool disposing)
{ }
public void Dispose()
{
lock (_syncLock)
{
if (!_disposed)
{
Dispose(true);

GC.SuppressFinalize(this);
}
}
}

#endregion

#region external calls to native implementations

[MethodImpl(MethodImplOptions.InternalCall)]
private extern void NativeInit();

[MethodImpl(MethodImplOptions.InternalCall)]
private extern void NativeDispose();

[MethodImpl(MethodImplOptions.InternalCall)]
private extern I2cTransferResult NativeTransmit(SpanByte writeBuffer, SpanByte readBuffer);

#endregion
}
}
30 changes: 30 additions & 0 deletions System.Device.I2c/I2cTransferResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace System.Device.I2c
{
/// <summary>
/// Provides information about whether the data transfers that the <see cref="I2cDevice.Read"/>, <see cref="I2cDevice.Write"/>, or <see cref="I2cDevice.WriteRead"/> method performed succeeded, and the actual number
/// of bytes the method transferred.
/// </summary>
public struct I2cTransferResult
{
[Diagnostics.DebuggerBrowsable(Diagnostics.DebuggerBrowsableState.Never)]
private readonly uint _bytesTransferred;

[Diagnostics.DebuggerBrowsable(Diagnostics.DebuggerBrowsableState.Never)]
private readonly I2cTransferStatus _status;

/// <summary>
/// The actual number of bytes that the operation actually transferred. The following table describes what this value represents for each method.
/// </summary>
public uint BytesTransferred { get => _bytesTransferred; }

/// <summary>
/// An enumeration value that indicates if the read or write operation transferred the full number of bytes that the method requested, or the reason
/// that the full transfer did not succeed. For WriteReadPartial, the value indicates whether the data for both the write and the read operations was entirely transferred.
/// </summary>
public I2cTransferStatus Status { get => _status; }
}
}
41 changes: 41 additions & 0 deletions System.Device.I2c/I2cTransferStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace System.Device.I2c
{
/// <summary>
/// Describes whether the data transfers that the <see cref="I2cDevice.Read"/>, <see cref="I2cDevice.Write"/>, or <see cref="I2cDevice.WriteRead"/> methods performed succeeded, or provides the reason that the transfers did not succeed.
/// </summary>
public enum I2cTransferStatus
{
/// <summary>
/// The transfer failed for an unknown reason.
/// </summary>
UnknownError,

/// <summary>
/// The data was entirely transferred. For WriteRead, the data for both the write and the read operations was entirely transferred.
/// For this status code, the value of the <see cref="I2cTransferResult.BytesTransferred"/> member that the method returns is the same as the size of the buffer
/// you specified when you called the method, or is equal to the sum of the sizes of two buffers that you specified for WriteRead.
/// </summary>
FullTransfer,

/// <summary>
/// The transfer failed due to the clock being stretched for too long. Ensure the clock line is not being held low.
/// </summary>
ClockStretchTimeout,

/// <summary>
/// The I2C device negatively acknowledged the data transfer before all of the data was transferred.
/// For this status code, the value of the <see cref="I2cTransferResult.BytesTransferred"/> member that the method returns is the number of bytes actually transferred.
/// For <see cref="I2cDevice.WriteRead"/>, the value is the sum of the number of bytes that the operation wrote and the number of bytes that the operation read.
/// </summary>
PartialTransfer,

/// <summary>
/// The bus address was not acknowledged. For this status code, the value of the <see cref="I2cTransferResult.BytesTransferred"/> member that the method returns of the method is 0.
/// </summary>
SlaveAddressNotAcknowledged,
}
}
9 changes: 4 additions & 5 deletions System.Device.I2c/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CSharp.BlankApplication")]
[assembly: AssemblyTitle("nanoFramework System.Device.I2c")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CSharp.BlankApplication")]
[assembly: AssemblyCompany(".NET nanoFramework contributors")]
[assembly: AssemblyProduct(".NET nanoFramework System.Device.I2c")]
[assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

////////////////////////////////////////////////////////////////
// update this whenever the native assembly signature changes //
[assembly: AssemblyNativeVersion("100.2.0.2")]
[assembly: AssemblyNativeVersion("100.0.0.1")]
////////////////////////////////////////////////////////////////

// Setting ComVisible to false makes the types in this assembly not visible
Expand Down
4 changes: 3 additions & 1 deletion System.Device.I2c/System.Device.I2c.nfproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</RootNamespace>
<AssemblyName>System.Device.I2c</AssemblyName>
<TargetFrameworkVersion>v1.0</TargetFrameworkVersion>
<!--<NF_IsCoreLibrary>True</NF_IsCoreLibrary>-->
<NF_IsCoreLibrary>True</NF_IsCoreLibrary>
<DocumentationFile>bin\$(Configuration)\System.Device.I2c.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
Expand Down Expand Up @@ -47,6 +47,8 @@
<Compile Include="I2cBusSpeed.cs" />
<Compile Include="I2cConnectionSettings.cs" />
<Compile Include="I2cDevice.cs" />
<Compile Include="I2cTransferResult.cs" />
<Compile Include="I2cTransferStatus.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
Expand Down

0 comments on commit 96aab04

Please sign in to comment.