diff --git a/src/Iot.Device.Bindings/CompatibilitySuppressions.xml b/src/Iot.Device.Bindings/CompatibilitySuppressions.xml index 626bebcfa6..c6dfb5a928 100644 --- a/src/Iot.Device.Bindings/CompatibilitySuppressions.xml +++ b/src/Iot.Device.Bindings/CompatibilitySuppressions.xml @@ -14,6 +14,13 @@ lib/net6.0/Iot.Device.Bindings.dll true + + CP0001 + T:Iot.Device.Ft232H.Ft232HI2c + lib/net6.0/Iot.Device.Bindings.dll + lib/net6.0/Iot.Device.Bindings.dll + true + CP0001 T:IoT.Device.Pn532.ErrorCode @@ -147,6 +154,13 @@ lib/netstandard2.0/Iot.Device.Bindings.dll true + + CP0001 + T:Iot.Device.Ft232H.Ft232HI2c + lib/netcoreapp3.1/Iot.Device.Bindings.dll + lib/netstandard2.0/Iot.Device.Bindings.dll + true + CP0001 T:Iot.Device.Common.ValueArray`1 @@ -161,6 +175,13 @@ lib/netstandard2.0/Iot.Device.Bindings.dll true + + CP0001 + T:Iot.Device.Ft232H.Ft232HI2c + lib/netstandard2.0/Iot.Device.Bindings.dll + lib/netstandard2.0/Iot.Device.Bindings.dll + true + CP0001 T:IoT.Device.Pn532.ErrorCode diff --git a/src/System.Device.Gpio.Tests/ProtocolTests.cs b/src/System.Device.Gpio.Tests/ProtocolTests.cs index 935c7b38bb..f138d925ef 100644 --- a/src/System.Device.Gpio.Tests/ProtocolTests.cs +++ b/src/System.Device.Gpio.Tests/ProtocolTests.cs @@ -1,13 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Threading; +using System.Collections.Generic; using System.Device.I2c; using System.Device.Pwm; +using System.Threading; using Iot.Device.Adc; using Iot.Device.Bmxx80; -using Xunit; +using Iot.Device.Board; using UnitsNet; +using Xunit; using static System.Device.Gpio.Tests.SetupHelpers; namespace System.Device.Gpio.Tests; @@ -100,6 +102,67 @@ public void I2C_I2cBus_MultipleDispose() bme280.Dispose(); } + [Fact] + [Trait("feature", "i2c")] + public void I2C_I2cBus_MultipleCreate() + { + I2cBus i2cBus = CreateI2cBusForBme280(); + + I2cDevice device1 = i2cBus.CreateDevice(Bmp280.DefaultI2cAddress); + device1.ReadByte(); + i2cBus.RemoveDevice(Bmp280.DefaultI2cAddress); + + I2cDevice device2 = i2cBus.CreateDevice(Bmp280.DefaultI2cAddress); + device2.ReadByte(); + } + + [Fact] + [Trait("feature", "i2c")] + public void I2C_I2cBus_MultipleCreateAndDispose() + { + I2cBus i2cBus = CreateI2cBusForBme280(); + + I2cDevice device1 = i2cBus.CreateDevice(Bmp280.DefaultI2cAddress); + device1.ReadByte(); + device1.Dispose(); + + I2cDevice device2 = i2cBus.CreateDevice(Bmp280.DefaultI2cAddress); + device2.ReadByte(); + device2.Dispose(); + } + + [Fact] + [Trait("feature", "i2c")] + public void I2C_I2cBus_Scan() + { + I2cBus i2cBus = CreateI2cBusForBme280(); + List addresses = i2cBus.PerformBusScan(); + Assert.NotNull(addresses); + } + + [Fact] + [Trait("feature", "i2c")] + public void I2C_I2cBus_ScanMultipleTimes() + { + I2cBus i2cBus = CreateI2cBusForBme280(); + + List addresses1 = i2cBus.PerformBusScan(); + Assert.NotNull(addresses1); + + List addresses2 = i2cBus.PerformBusScan(); + Assert.NotNull(addresses2); + } + + [Fact] + [Trait("feature", "i2c")] + public void I2C_I2cBus_HasBmp280Present() + { + I2cBus i2cBus = CreateI2cBusForBme280(); + List addresses = i2cBus.PerformBusScan(); + Assert.NotEmpty(addresses); + Assert.Contains(Bmp280.DefaultI2cAddress, addresses); + } + [Fact] [Trait("feature", "pwm")] [Trait("feature", "spi")] diff --git a/src/devices/Board/I2cBusManager.cs b/src/devices/Board/I2cBusManager.cs index 049e7e8fe6..1a23186ba8 100644 --- a/src/devices/Board/I2cBusManager.cs +++ b/src/devices/Board/I2cBusManager.cs @@ -68,13 +68,8 @@ public I2cBusManager(Board board, int bus, int[]? pins, I2cBus busInstance) /// No test is performed whether the given device exists and is usable public override I2cDevice CreateDevice(int deviceAddress) { - if (_devices.TryGetValue(deviceAddress, out I2cDevice? device)) - { - return device; - } - I2cDevice newDevice = _busInstance.CreateDevice(deviceAddress); - _devices.Add(deviceAddress, newDevice); + _devices[deviceAddress] = newDevice; return newDevice; } diff --git a/src/devices/Board/tests/BoardTests.cs b/src/devices/Board/tests/BoardTests.cs index 68e8471f15..b9c15fb29f 100644 --- a/src/devices/Board/tests/BoardTests.cs +++ b/src/devices/Board/tests/BoardTests.cs @@ -185,6 +185,34 @@ public void TwoI2cDevicesCanSharePins() ctrl.OpenPin(0); } + [Fact] + public void CreateAndRemoveI2cDevice() + { + using Board board = CreateBoard(); + I2cBus bus = board.CreateOrGetI2cBus(0); + + I2cDevice device1 = bus.CreateDevice(0x55); + device1.ReadByte(); + bus.RemoveDevice(0x55); + + I2cDevice device2 = bus.CreateDevice(0x55); + device2.ReadByte(); + } + + [Fact] + public void CreateAndDisposeI2cDevice() + { + using Board board = CreateBoard(); + I2cBus bus = board.CreateOrGetI2cBus(0); + + I2cDevice device1 = bus.CreateDevice(0x55); + device1.ReadByte(); + device1.Dispose(); + + I2cDevice device2 = bus.CreateDevice(0x55); + device2.ReadByte(); + } + [Fact] public void CreateSpiDeviceDefault() { diff --git a/src/devices/Ft232H/Ft232H.csproj b/src/devices/Ft232H/Ft232H.csproj index 0cfcbde535..86d985b7d6 100644 --- a/src/devices/Ft232H/Ft232H.csproj +++ b/src/devices/Ft232H/Ft232H.csproj @@ -9,8 +9,8 @@ - + diff --git a/src/devices/Ft232H/Ft232HI2cBus.cs b/src/devices/Ft232H/Ft232HI2cBus.cs index 49a110a77b..0347881058 100644 --- a/src/devices/Ft232H/Ft232HI2cBus.cs +++ b/src/devices/Ft232H/Ft232HI2cBus.cs @@ -15,7 +15,7 @@ namespace Iot.Device.Ft232H /// internal class Ft232HI2cBus : I2cBus { - private HashSet _usedAddresses = new HashSet(); + private HashSet? _usedAddresses = null; /// /// Store the FTDI Device Information @@ -35,23 +35,34 @@ public Ft232HI2cBus(Ftx232HDevice deviceInformation) /// public override I2cDevice CreateDevice(int deviceAddress) { + _usedAddresses ??= new HashSet(); if (!_usedAddresses.Add(deviceAddress)) { throw new ArgumentException($"Device with address 0x{deviceAddress,0X2} is already open.", nameof(deviceAddress)); } - return new Ft232HI2c(this, deviceAddress); + return CreateDeviceNoCheck(deviceAddress); + } + + internal I2cDevice CreateDeviceNoCheck(int deviceAddress) + { + return new Ft232HI2cDevice(this, deviceAddress); } /// public override void RemoveDevice(int deviceAddress) { - if (!_usedAddresses.Remove(deviceAddress)) + if (!RemoveDeviceNoCheck(deviceAddress)) { throw new ArgumentException($"Device with address 0x{deviceAddress,0X2} was not open.", nameof(deviceAddress)); } } + internal bool RemoveDeviceNoCheck(int deviceAddress) + { + return _usedAddresses?.Remove(deviceAddress) ?? false; + } + internal void Read(int deviceAddress, Span buffer) { DeviceInformation.I2cStart(); diff --git a/src/devices/Ft232H/Ft232HI2c.cs b/src/devices/Ft232H/Ft232HI2cDevice.cs similarity index 71% rename from src/devices/Ft232H/Ft232HI2c.cs rename to src/devices/Ft232H/Ft232HI2cDevice.cs index b925792866..0c9a417d2e 100644 --- a/src/devices/Ft232H/Ft232HI2c.cs +++ b/src/devices/Ft232H/Ft232HI2cDevice.cs @@ -9,17 +9,19 @@ namespace Iot.Device.Ft232H /// /// I2C Device for FT232H /// - public class Ft232HI2c : I2cDevice + public class Ft232HI2cDevice : I2cDevice { private Ft232HI2cBus _i2cBus; private int _deviceAddress; private I2cConnectionSettings _settings; + private bool _shouldDisposeBus; - internal Ft232HI2c(Ft232HI2cBus i2cBus, int deviceAddress) + internal Ft232HI2cDevice(Ft232HI2cBus i2cBus, int deviceAddress, bool shouldDisposeBus = false) { _i2cBus = i2cBus; _deviceAddress = deviceAddress; _settings = new I2cConnectionSettings((int)i2cBus.DeviceInformation.LocId, deviceAddress); + _shouldDisposeBus = shouldDisposeBus; } /// @@ -47,9 +49,22 @@ public override void WriteRead(ReadOnlySpan writeBuffer, Span readBu /// protected override void Dispose(bool disposing) { - _i2cBus?.RemoveDevice(_deviceAddress); - _i2cBus = null!; + if (_i2cBus != null) + { + if (_shouldDisposeBus) + { + _i2cBus.Dispose(); + } + else + { + _i2cBus.RemoveDeviceNoCheck(_deviceAddress); + } + + _i2cBus = null!; + } + _settings = null!; + base.Dispose(disposing); }