diff --git a/Directory.Build.props b/Directory.Build.props index 9e21d3feb9..ffeba7079e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -17,7 +17,7 @@ C# - 9 + 12 true diff --git a/eng/ArduinoCsCI.cmd b/eng/ArduinoCsCI.cmd index 733b34a6f1..76b0d92a31 100644 --- a/eng/ArduinoCsCI.cmd +++ b/eng/ArduinoCsCI.cmd @@ -5,7 +5,7 @@ REM Second argument is either "Debug" or "Release" if %1!==! goto :usage REM Defines the revision to check out in the ExtendedConfigurableFirmata repo -set FIRMATA_SIMULATOR_CHECKOUT_REVISION=a354343cebc35964450dfa01dba2cd996065fd5c +set FIRMATA_SIMULATOR_CHECKOUT_REVISION=f70a361765adedd5752a7578d5bb77e55f268e38 set RUN_COMPILER_TESTS=FALSE choco install -y --no-progress arduino-cli diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props index c521aaa0c9..bcc891516c 100644 --- a/samples/Directory.Build.props +++ b/samples/Directory.Build.props @@ -13,7 +13,7 @@ $(MSBuildThisFileDirectory)../src/System.Device.Gpio/ $(MSBuildThisFileDirectory)../src/Iot.Device.Bindings/ enable - 9 + 12 $(NoWarn);NETSDK1023 diff --git a/src/System.Device.Gpio/System.Device.Gpio.csproj b/src/System.Device.Gpio/System.Device.Gpio.csproj index 017bb62c03..b561cb95e4 100644 --- a/src/System.Device.Gpio/System.Device.Gpio.csproj +++ b/src/System.Device.Gpio/System.Device.Gpio.csproj @@ -1,7 +1,6 @@  net8.0 - 10 enable true true diff --git a/src/devices/Arduino/tests/Arduino.Tests.csproj b/src/devices/Arduino/tests/Arduino.Tests.csproj index 9c22a2e727..5edac0e9b9 100644 --- a/src/devices/Arduino/tests/Arduino.Tests.csproj +++ b/src/devices/Arduino/tests/Arduino.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultSampleTfms) false - latest false requires!=hardware diff --git a/src/devices/Blinkt/Blinkt.csproj b/src/devices/Blinkt/Blinkt.csproj index 2b43b907b7..92dea8e186 100644 --- a/src/devices/Blinkt/Blinkt.csproj +++ b/src/devices/Blinkt/Blinkt.csproj @@ -4,7 +4,6 @@ $(DefaultBindingTfms) false - 9 diff --git a/src/devices/Bmm150/tests/Bmm150.Tests.csproj b/src/devices/Bmm150/tests/Bmm150.Tests.csproj index b48de1bb19..35b975c3dd 100644 --- a/src/devices/Bmm150/tests/Bmm150.Tests.csproj +++ b/src/devices/Bmm150/tests/Bmm150.Tests.csproj @@ -1,7 +1,6 @@  $(DefaultTestTfms) - 9 false false diff --git a/src/devices/Bmxx80/tests/Bmxx80.Tests.csproj b/src/devices/Bmxx80/tests/Bmxx80.Tests.csproj index 77447bc048..f2352cc3a2 100644 --- a/src/devices/Bmxx80/tests/Bmxx80.Tests.csproj +++ b/src/devices/Bmxx80/tests/Bmxx80.Tests.csproj @@ -1,7 +1,6 @@  $(DefaultTestTfms) - 9 false false diff --git a/src/devices/Board/Board.csproj b/src/devices/Board/Board.csproj index e218114c1b..2dea571fbb 100644 --- a/src/devices/Board/Board.csproj +++ b/src/devices/Board/Board.csproj @@ -2,7 +2,6 @@ $(DefaultBindingTfms) false - preview Iot.Device.Board diff --git a/src/devices/Board/tests/Board.Tests.csproj b/src/devices/Board/tests/Board.Tests.csproj index 54e283eab4..8f9cff0789 100644 --- a/src/devices/Board/tests/Board.Tests.csproj +++ b/src/devices/Board/tests/Board.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultTestTfms) false - latest false Iot.Device.Board.Tests diff --git a/src/devices/Button/tests/Button.tests.csproj b/src/devices/Button/tests/Button.tests.csproj index 6852f81b22..e3043ced11 100644 --- a/src/devices/Button/tests/Button.tests.csproj +++ b/src/devices/Button/tests/Button.tests.csproj @@ -3,7 +3,6 @@ $(DefaultTestTfms) false - latest false Iot.Device.Button.Tests diff --git a/src/devices/Camera/Camera/Camera.csproj b/src/devices/Camera/Camera/Camera.csproj index 74126a817f..673ec0371a 100644 --- a/src/devices/Camera/Camera/Camera.csproj +++ b/src/devices/Camera/Camera/Camera.csproj @@ -3,7 +3,6 @@ $(DefaultBindingTfms) enable - Latest Iot.Device.$(MSBuildProjectName.Replace(" ", "_")) diff --git a/src/devices/Camera/samples/Camera.Samples/Camera.Samples.csproj b/src/devices/Camera/samples/Camera.Samples/Camera.Samples.csproj index 2964447359..b08d98eca1 100644 --- a/src/devices/Camera/samples/Camera.Samples/Camera.Samples.csproj +++ b/src/devices/Camera/samples/Camera.Samples/Camera.Samples.csproj @@ -4,7 +4,6 @@ $(DefaultSampleTfms) enable enable - Latest Exe diff --git a/src/devices/Camera/tests/FakeVideoCapture/FakeVideoCapture.csproj b/src/devices/Camera/tests/FakeVideoCapture/FakeVideoCapture.csproj index b88d961480..29177fbc7c 100644 --- a/src/devices/Camera/tests/FakeVideoCapture/FakeVideoCapture.csproj +++ b/src/devices/Camera/tests/FakeVideoCapture/FakeVideoCapture.csproj @@ -5,7 +5,6 @@ $(DefaultSampleTfms) enable enable - Latest diff --git a/src/devices/Camera/tests/TestCamera/TestCamera.csproj b/src/devices/Camera/tests/TestCamera/TestCamera.csproj index 7f444ef168..68a18ae78d 100644 --- a/src/devices/Camera/tests/TestCamera/TestCamera.csproj +++ b/src/devices/Camera/tests/TestCamera/TestCamera.csproj @@ -4,7 +4,6 @@ $(DefaultTestTfms) enable enable - Latest false diff --git a/src/devices/CharacterLcd/tests/CharacterLcd.Tests.csproj b/src/devices/CharacterLcd/tests/CharacterLcd.Tests.csproj index 498b77a216..ff8ad98229 100644 --- a/src/devices/CharacterLcd/tests/CharacterLcd.Tests.csproj +++ b/src/devices/CharacterLcd/tests/CharacterLcd.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultTestTfms) - 9 false diff --git a/src/devices/Charlieplex/tests/Charlieplex.Tests.csproj b/src/devices/Charlieplex/tests/Charlieplex.Tests.csproj index c125e9aae1..ee650b360f 100644 --- a/src/devices/Charlieplex/tests/Charlieplex.Tests.csproj +++ b/src/devices/Charlieplex/tests/Charlieplex.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultTestTfms) - 9 false diff --git a/src/devices/Common/Common.csproj b/src/devices/Common/Common.csproj index 4dbd080868..b0297d729f 100644 --- a/src/devices/Common/Common.csproj +++ b/src/devices/Common/Common.csproj @@ -12,6 +12,7 @@ + diff --git a/src/devices/Common/System/Device/I2c/I2cSimulatedDeviceBase.cs b/src/devices/Common/System/Device/I2c/I2cSimulatedDeviceBase.cs new file mode 100644 index 0000000000..928bf5be22 --- /dev/null +++ b/src/devices/Common/System/Device/I2c/I2cSimulatedDeviceBase.cs @@ -0,0 +1,285 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using UnitsNet; + +namespace System.Device.I2c; + +/// +/// This class can be used to create a simulated I2C device. +/// Derive from it and implement the and commands +/// to behave as expected. +/// Can also serve as base for a testing mock. +/// +public abstract class I2cSimulatedDeviceBase : I2cDevice +{ + private bool _disposed; + private Dictionary _registerMap; + private byte _currentRegister; + + /// + /// Default constructor + /// + /// The connection settings for this device. + public I2cSimulatedDeviceBase(I2cConnectionSettings settings) + { + ConnectionSettings = settings; + _registerMap = new Dictionary(); + _disposed = false; + _currentRegister = 0; + } + + /// + /// The registermap of this device. + /// This should only be accessed from a derived class, except for test purposes. + /// + public Dictionary RegisterMap => _registerMap; + + /// + /// The active connection settings + /// + public override I2cConnectionSettings ConnectionSettings { get; } + + /// + /// The active register. + /// Can be set to mimic some non-standard behavior of setting a register (or if reading increases + /// the register pointer, which is the case on some chips) + /// + protected byte CurrentRegister + { + get + { + return _currentRegister; + } + set + { + _currentRegister = value; + } + } + + /// + /// Reads a byte from the bus + /// + /// + /// The instance is disposed already + /// + public override byte ReadByte() + { + if (_disposed) + { + throw new ObjectDisposedException("This instance is disposed"); + } + + byte[] buffer = new byte[1]; + if (WriteRead([], buffer) == 1) + { + return buffer[0]; + } + + throw new IOException("Unable to read a byte from the device"); + } + + /// + /// This method implements the read operation from the device. + /// + /// Buffer with input data to the device, buffer[0] is usually the command byte + /// The return data from the device + /// How many bytes where read. Should usually match the length of the output buffer + /// This doesn't use as argument type to be mockable. Be sure + /// to use this method in mocks, not any that take or , as that + /// will cause runtime exceptions + public abstract int WriteRead(byte[] inputBuffer, byte[] outputBuffer); + + /// + public override void Read(Span buffer) + { + byte[] buffer2 = buffer.ToArray(); + if (WriteRead([], buffer2) == buffer.Length) + { + buffer2.CopyTo(buffer); + return; + } + + throw new IOException($"Unable to read {buffer.Length} bytes from the device"); + } + + /// + public override void WriteByte(byte value) + { + if (WriteRead([value], []) == 1) + { + return; + } + + throw new IOException("Unable to write a byte to the device"); + } + + /// + public override void Write(ReadOnlySpan buffer) + { + WriteRead(buffer.ToArray(), []); + } + + /// + public override void WriteRead(ReadOnlySpan writeBuffer, Span readBuffer) + { + byte[] outBuffer = new byte[readBuffer.Length]; + if (WriteRead(writeBuffer.ToArray(), outBuffer) != readBuffer.Length) + { + throw new IOException($"Unable to read {readBuffer.Length} bytes from the device"); + } + + outBuffer.CopyTo(readBuffer); + } + + /// + protected override void Dispose(bool disposing) + { + _disposed = true; + base.Dispose(disposing); + } + + /// + public override ComponentInformation QueryComponentInformation() + { + var self = new ComponentInformation(this, "Simulated I2C Device"); + self.Properties["BusNo"] = ConnectionSettings.BusId.ToString(CultureInfo.InvariantCulture); + self.Properties["DeviceAddress"] = $"0x{ConnectionSettings.DeviceAddress:x2}"; + return self; + } + + /// + /// Base class for generic register access + /// + public abstract record class RegisterBase : IComparable + { + /// + /// Writes the register, regardless of its actual type + /// + /// The value to write + public abstract void WriteRegister(int value); + + /// + /// Reads the register value regardless of its actual type + /// + /// The register value, sign-extended to int + public abstract int ReadRegister(); + + /// + public abstract int CompareTo(object? obj); + } + + /// + /// Represents a register value + /// + /// Size of the register, usually byte or int + public record class Register : RegisterBase + where T : struct, IEquatable, INumber, IComparable + { + /// + /// Event that is raised when the register is written + /// + private readonly Func? _registerUpdateHandler; + + /// + /// Event that is raised to read the register. Gets the internal value of the register + /// and returns the value the client should see (e.g a random measurement value) + /// + private readonly Func? _registerReadHandler; + + private T _value; + + /// + /// Create a new register + /// + public Register() + : this(default(T)) + { + } + + /// + /// Creates a new register + /// + /// The initial (power-on-reset) value of the register + public Register(T initialValue) + { + _value = initialValue; + } + + /// + /// Creates a new register with handlers + /// + /// The initial value of the register at power-up + /// A handler for a register write. Can be null. + /// A handler for a register read. Can be null. + public Register(T initialValue, Func? updateHandler, Func? readHandler) + { + _value = initialValue; + _registerUpdateHandler = updateHandler; + _registerReadHandler = readHandler; + } + + /// + /// The current value of the register + /// + public T Value + { + get + { + if (_registerReadHandler != null) + { + return _registerReadHandler(_value); + } + + return _value; + } + set + { + if (_registerUpdateHandler != null) + { + _value = _registerUpdateHandler(value); + return; + } + + _value = value; + } + } + + /// + public override void WriteRegister(int value) + { + Value = T.CreateChecked(value); + } + + /// + public override int ReadRegister() + { + return int.CreateChecked(Value); + } + + /// + public override int CompareTo(object? obj) + { + if (obj == null) + { + return 1; + } + + if (obj is Register t1) + { + return _value.CompareTo(t1._value); + } + + throw new ArgumentException("These types can't be compared"); + } + } +} diff --git a/src/devices/Common/tests/Common.Tests.csproj b/src/devices/Common/tests/Common.Tests.csproj index 00b25bf31b..76ad6b58d3 100644 --- a/src/devices/Common/tests/Common.Tests.csproj +++ b/src/devices/Common/tests/Common.Tests.csproj @@ -4,6 +4,5 @@ false false true - 10 \ No newline at end of file diff --git a/src/devices/Directory.Build.props b/src/devices/Directory.Build.props index 284dd5f101..e772863f1d 100644 --- a/src/devices/Directory.Build.props +++ b/src/devices/Directory.Build.props @@ -14,7 +14,6 @@ $(MSBuildThisFileDirectory)$(SystemDeviceModelProjectName)/$(SystemDeviceModelProjectName).csproj Common $(MSBuildThisFileDirectory)$(CommonProjectName)/$(CommonProjectName).csproj - latest enable diff --git a/src/devices/Gpio/Iot.Device.Gpio.csproj b/src/devices/Gpio/Iot.Device.Gpio.csproj index dbed440ee4..9f3bce500d 100644 --- a/src/devices/Gpio/Iot.Device.Gpio.csproj +++ b/src/devices/Gpio/Iot.Device.Gpio.csproj @@ -2,7 +2,6 @@ $(DefaultBindingTfms) true - latest enable false diff --git a/src/devices/Gpio/README.md b/src/devices/Gpio/README.md index 5af2b9808f..5f1751afcf 100644 --- a/src/devices/Gpio/README.md +++ b/src/devices/Gpio/README.md @@ -32,11 +32,11 @@ When adding an existing GpioPin, by default, the new pin allocation will directl | Board | Driver | | :-: | :-: | | Orange Pi 4 | [OrangePi4Driver](./Drivers/OrangePi4Driver.cs) | -| Orange Pi Lite | [OrangePiLiteDriver](./Drivers/OrangePiLiteDriver.cs) | +| Orange Pi Lite | [OrangePiLiteDriver](./Drivers/OrangePiLiteDriver.cs) | | Orange Pi Lite 2 | [OrangePiLite2Driver](./Drivers/OrangePiLite2Driver.cs) | | Orange Pi Zero | [OrangePiZeroDriver](./Drivers/OrangePiZeroDriver.cs) | | Orange Pi Zero 2 | [OrangePiZero2Driver](./Drivers/OrangePiZero2Driver.cs) | -| Rock Pi 4B Plus | [RockPi4bPlusDriver](./Drivers/RockPi4bPlusDriver.cs) | +| Rock Pi 4B Plus | [RockPi4BPlusDriver](./Drivers/RockPi4BPlusDriver.cs) | | Orange Pi PC | [OrangePiPCDriver](./Drivers/OrangePiPCDriver.cs) | ## Benchmarks @@ -47,7 +47,7 @@ The test uses different GPIO drivers to quickly switch the state of GPIO, and us Benchmarking with **Orange Pi Zero**, select GPIO 6 (Logical). The operating system is Armbian buster, Linux kernel version is 5.10.16, and .NET version is 5.0.3. -| Drivers| Language | Library Version | Test Date | Average Frequency | | +| Drivers | Language | Library Version | Test Date | Average Frequency | | | :-: | :-: | :-: | :-: | :-: | :-: | | SunxiDriver | C# | - | 2020-02-20 | 185 KHz | ![sunxi](./imgs/SunxiDriver/sunxi.jpg) | | SysFsDriver | C# | System.Device.Gpio 1.3.0 | 2020-02-20 | 692 Hz | ![sysfs](./imgs/SunxiDriver/sysfs.jpg) | @@ -58,7 +58,7 @@ Benchmarking with **Orange Pi Zero**, select GPIO 6 (Logical). The operating sys Benchmarking with **Orange Pi 4**, select GPIO 150 (Logical). The operating system is Armbian buster, Linux kernel version is 5.10.16, and .NET version is 5.0.3. -| Drivers| Language | Library Version | Test Date | Average Frequency | | +| Drivers | Language | Library Version | Test Date | Average Frequency | | | :-: | :-: | :-: | :-: | :-: | :-: | | RockchipDriver | C# | - | 2020-02-22 | 516 KHz | ![rockchip](./imgs/RockchipDriver/rockchip.jpg) | | SysFsDriver | C# | System.Device.Gpio 1.3.0 | 2020-02-22 | 4.27 KHz | ![sysfs](./imgs/RockchipDriver/sysfs.jpg) | diff --git a/src/devices/Gpio/samples/Iot.Device.Gpio.Samples.csproj b/src/devices/Gpio/samples/Iot.Device.Gpio.Samples.csproj index 304a274563..56500b9db8 100644 --- a/src/devices/Gpio/samples/Iot.Device.Gpio.Samples.csproj +++ b/src/devices/Gpio/samples/Iot.Device.Gpio.Samples.csproj @@ -4,7 +4,6 @@ Exe $(DefaultSampleTfms) enable - latest diff --git a/src/devices/Gpio/tests/Gpio.Tests.csproj b/src/devices/Gpio/tests/Gpio.Tests.csproj index 09c2d6fffe..7ea0e5e3f2 100644 --- a/src/devices/Gpio/tests/Gpio.Tests.csproj +++ b/src/devices/Gpio/tests/Gpio.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultTestTfms) false - latest false Iot.Device.Gpio.Tests diff --git a/src/devices/Gui/Gui.csproj b/src/devices/Gui/Gui.csproj index 81f4f99218..5cb43ac168 100644 --- a/src/devices/Gui/Gui.csproj +++ b/src/devices/Gui/Gui.csproj @@ -4,7 +4,6 @@ $(DefaultBindingTfms) false - 9 Iot.Device.Gui True diff --git a/src/devices/Gui/tests/Gui.Tests.csproj b/src/devices/Gui/tests/Gui.Tests.csproj index e9125c595f..af9331d6eb 100644 --- a/src/devices/Gui/tests/Gui.Tests.csproj +++ b/src/devices/Gui/tests/Gui.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultSampleTfms) - 10 false false diff --git a/src/devices/Hx711/HX711.csproj b/src/devices/Hx711/HX711.csproj index 3e69cfd065..83773a5b48 100644 --- a/src/devices/Hx711/HX711.csproj +++ b/src/devices/Hx711/HX711.csproj @@ -2,7 +2,6 @@ $(DefaultBindingTfms) false - 10 diff --git a/src/devices/Hx711I2c/Hx711I2c.csproj b/src/devices/Hx711I2c/Hx711I2c.csproj index 9b6809df74..0378bf11e1 100644 --- a/src/devices/Hx711I2c/Hx711I2c.csproj +++ b/src/devices/Hx711I2c/Hx711I2c.csproj @@ -2,7 +2,6 @@ $(DefaultBindingTfms) false - 10 diff --git a/src/devices/Ili934x/tests/Ili934x.Tests.csproj b/src/devices/Ili934x/tests/Ili934x.Tests.csproj index 9bdab6ac67..32f4b5b4b3 100644 --- a/src/devices/Ili934x/tests/Ili934x.Tests.csproj +++ b/src/devices/Ili934x/tests/Ili934x.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultSampleTfms) - 10 false false diff --git a/src/devices/Ina236/Ina236.cs b/src/devices/Ina236/Ina236.cs new file mode 100644 index 0000000000..3f20bee6cf --- /dev/null +++ b/src/devices/Ina236/Ina236.cs @@ -0,0 +1,369 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Device; +using System.Device.I2c; +using System.Device.Model; +using UnitsNet; +using static System.Math; + +namespace Iot.Device.Adc +{ + /// + /// INA236 Bidirectional Current/Power monitor. + /// + /// The INA236 current shunt and power monitor with an I2C interface. + /// The INA236 monitors both shunt drop and supply voltage, with programmable conversion + /// times and filtering. A programmable calibration value, combined with an internal multiplier, + /// enables direct readouts in amperes. An additional multiplying register calculates power in watts. + /// + /// + [Interface("INA236 Bidirectional Current/Power monitor")] + public class Ina236 : IDisposable + { + /// + /// The default I2C Address for this device. + /// According to the datasheet, the device comes in two variants, A and B. + /// Type A has addresses 0x40 to 0x43, depending on whether the ADDR pin is connected to GND, VS, SDA or SCL. + /// Type B has addresses 0x44 to 0x47, depending on the ADDR pin. + /// + public const int DefaultI2cAddress = 0x40; + private I2cDevice _i2cDevice; + private ElectricResistance _shuntResistance; + private ElectricCurrent _currentLsb; + private ElectricCurrent _maxCurrent; + private ElectricPotential _voltageLsb; + + /// + /// Construct an Ina236 device using an I2cDevice + /// + /// The I2cDevice initialized to communicate with the INA236. + /// Maximum expected current. Typical values are 8-10 Amps. + /// The resistance of the shunt between input and output. + /// Example breakout boards from manufacturers such as Adafruit have 0.008 Ohms, so try this + /// value if you are unsure. + /// The power dissipation at the resistor is P = I*I*R at the maximum current. + public Ina236(I2cDevice i2cDevice, ElectricResistance shuntResistance, ElectricCurrent maxCurrent) + { + _i2cDevice = i2cDevice ?? throw new ArgumentNullException(nameof(i2cDevice)); + _shuntResistance = shuntResistance; + if (_shuntResistance <= ElectricResistance.Zero) + { + throw new ArgumentOutOfRangeException(nameof(shuntResistance), "The shuntResistance parameter must be greater than zero"); + } + + _maxCurrent = maxCurrent; + + Reset(_shuntResistance, _maxCurrent); + } + + /// + /// Reset the INA236 to default values; + /// + [Command] + public void Reset(ElectricResistance shuntResistance, ElectricCurrent current) + { + // Reset the device by sending a value to the configuration register with the reset bit set. + WriteRegister(Ina236Register.Configuration, 0x8000); + + ushort deviceId = ReadRegisterUnsigned(Ina236Register.DeviceId); + + if ((deviceId & 0xFFF0) != 0xa080) + { + throw new InvalidOperationException($"The device on I2C address {_i2cDevice.ConnectionSettings.DeviceAddress} doesn't seem to be an INA236. Device ID was {deviceId:X4} instead of 0xA080"); + } + + // See datasheet. Use twice the value to allow later rounding + ElectricCurrent currentLsbMinimum = current / Pow(2.0, 15) * 2; + double exactCalibrationValue = 0.00512 / (currentLsbMinimum.Amperes * shuntResistance.Ohms); + int valueToSet = (int)exactCalibrationValue; + if (valueToSet > 0xFFFF) + { + throw new InvalidOperationException("Invalid combination of settings - the calibration value is out of spec"); + } + + // Reverse calculation, to get the exact lsb + // Solve this for x: + // calibrationValue = 0.00512 / (x * resistance) // * (x * resistance) + // calibrationValue * (x * resistance) = 0.00512 // / resistance + // calibrationValue * x = 0.00512 / resistance // / calibrationvalue + // x = 0.00512 / resistance / calibrationValue + double exactLsbMinimum = 0.00512 / shuntResistance.Ohms / valueToSet; + + _currentLsb = ElectricCurrent.FromAmperes(exactLsbMinimum); + + // The LSB of the shunt voltage register is 2.5uV if ADCRANGE==0, otherwise it's 625nV. We currently + // do not support ADCRANGE=1, to keep things simple. + _voltageLsb = ElectricPotential.FromMicrovolts(2.5); + WriteRegister(Ina236Register.Calibration, (ushort)valueToSet); + } + + /// + /// Property representing the Operating mode of the INA236 + /// + /// + /// This allows the user to selects continuous, triggered, or power-down mode of operation along with which of the shunt and bus voltage measurements are made. + /// + [Property] + public Ina236OperatingMode OperatingMode + { + get + { + return (Ina236OperatingMode)(ReadRegisterUnsigned(Ina236Register.Configuration) & (ushort)Ina236OperatingMode.ModeMask); + } + set + { + int regValue = ReadRegisterUnsigned(Ina236Register.Configuration); + + regValue &= ~0b111; + regValue |= (int)value; + + WriteRegister(Ina236Register.Configuration, (ushort)regValue); + } + } + + /// + /// How many samples should be combined into one result. + /// A high value returns less often a new reading, but is more stable. + /// + /// Valid values are: 1, 4, 16, 64, 128, 256, 512 and 1024. Other values will be rounded accordingly. + /// + /// + [Property] + public uint AverageOverNoSamples + { + get + { + int reg = (ReadRegisterUnsigned(Ina236Register.Configuration) >> 9) & 0x7; + return reg switch + { + 0b000 => 1, + 0b001 => 4, + 0b010 => 16, + 0b011 => 64, + 0b100 => 128, + 0b101 => 256, + 0b110 => 512, + 0b111 => 1024, + _ => throw new InvalidOperationException("This is not possible") + }; + } + set + { + int valueToSet = value switch + { + <= 1 => 0b000, + <= 4 => 0b001, + <= 16 => 0b010, + <= 64 => 0b011, + <= 128 => 0b100, + <= 256 => 0b101, + <= 512 => 0b110, + >= 513 => 0b111, + }; + + int reg = ReadRegisterUnsigned(Ina236Register.Configuration) & 0xF1FF; + reg = reg | (valueToSet << 9); + WriteRegister(Ina236Register.Configuration, (ushort)reg); + } + } + + /// + /// Conversion time for a single bus value, in microseconds + /// + /// Valid values are: 140, 204, 332, 588, 1100 (default), 2116, 4156 and 8244us. Other values will be rounded + public int BusConversionTime + { + get + { + int reg = (ReadRegisterUnsigned(Ina236Register.Configuration) >> 6) & 0x7; + return ConversionPeriodFromValue(reg); + } + + set + { + int valueToSet = ValueFromConversionPeriod(value); + int reg = ReadRegisterUnsigned(Ina236Register.Configuration) & 0xFE3F; + reg = reg | (valueToSet << 6); + WriteRegister(Ina236Register.Configuration, (ushort)reg); + } + } + + /// + /// Conversion time for a single shunt value, in microseconds + /// + /// Valid values are: 140, 204, 332, 588, 1100 (default), 2116, 4156 and 8244us. Other values will be rounded + public int ShuntConversionTime + { + get + { + int reg = (ReadRegisterUnsigned(Ina236Register.Configuration) >> 3) & 0x7; + return ConversionPeriodFromValue(reg); + } + + set + { + int valueToSet = ValueFromConversionPeriod(value); + int reg = ReadRegisterUnsigned(Ina236Register.Configuration) & 0xFFC7; + reg = reg | (valueToSet << 3); + WriteRegister(Ina236Register.Configuration, (ushort)reg); + } + } + + /// + /// Converts the given conversion period in us into the binary equivalent + /// + /// Period in microseconds + /// An integer value to be set to the register (with appropriate shift, used for VBUSCT and VSHCT + /// in the configuration register) + private int ValueFromConversionPeriod(int period) + { + return period switch + { + <= 140 => 0b000, + <= 204 => 0b001, + <= 332 => 0b010, + <= 588 => 0b011, + <= 1100 => 0b100, + <= 2116 => 0b101, + <= 4156 => 0b110, + >= 4157 => 0b111 + }; + } + + /// + /// Inverse of the above + /// + /// The time period + /// The bit value for the conversion register + private int ConversionPeriodFromValue(int period) + { + return period switch + { + 0b000 => 140, + 0b001 => 204, + 0b010 => 332, + 0b011 => 588, + 0b100 => 1100, + 0b101 => 2116, + 0b110 => 4156, + 0b111 => 8244, + _ => throw new InvalidOperationException("This cannot really happen") + }; + } + + /// + /// Dispose instance + /// + public void Dispose() + { + _i2cDevice?.Dispose(); + _i2cDevice = null!; + } + + /// + /// Read the measured shunt voltage. + /// + /// The shunt potential difference + /// The LSB is 2.5uV when ADCRANGE=0 + [Telemetry("ShuntVoltage")] + public ElectricPotential ReadShuntVoltage() + { + return ReadRegisterUnsigned(Ina236Register.ShuntVoltage) * _voltageLsb; + } + + /// + /// Read the measured Bus voltage. + /// This is the voltage on the primary side of the shunt. + /// + /// The Bus potential (voltage) + /// The LSB is 1.6mV. + [Telemetry("BusVoltage")] + public ElectricPotential ReadBusVoltage() + { + return ReadRegisterUnsigned(Ina236Register.BusVoltage) * ElectricPotential.FromMillivolts(1.6); + } + + /// + /// Read the calculated current through the INA236. + /// + /// + /// This value is determined by an internal calculation using the calibration register and the read shunt voltage and then scaled. + /// The value can be negative, when power flows to the bus. + /// + /// The calculated current + [Telemetry("Current")] + public ElectricCurrent ReadCurrent() + { + return ReadRegisterSigned(Ina236Register.Current) * _currentLsb; + } + + /// + /// Reads the current power consumed by the attached device. + /// + /// The power being used + /// Clarify whether this register is signed or unsigned. Since it is the product of the current and the bus voltage + /// registers, it should be possible to get a negative value, but the documentation says it's always positive + [Telemetry("Power")] + public Power ReadPower() + { + return Power.FromWatts(ReadRegisterUnsigned(Ina236Register.Power) * _currentLsb.Amperes * 32); + } + + /// + /// Read a register from the INA236 device + /// + /// The register to read. + /// Am unsiged short integer representing the regsiter contents. + private ushort ReadRegisterUnsigned(Ina236Register register) + { + Span buffer = stackalloc byte[2]; + + byte registerNumber = (byte)register; + // set a value in the buffer representing the register that we want to read and send it to the INA219 + _i2cDevice.WriteRead(new ReadOnlySpan(ref registerNumber), buffer); + + // massage the big endian value read from the INA219 unto a ushort. + return BinaryPrimitives.ReadUInt16BigEndian(buffer); + } + + /// + /// Read a register from the INA236 device + /// + /// The register to read. + /// A signed short integer representing the regsiter contents. + private short ReadRegisterSigned(Ina236Register register) + { + Span buffer = stackalloc byte[2]; + + byte registerNumber = (byte)register; + // set a value in the buffer representing the register that we want to read and send it to the INA219 + _i2cDevice.WriteRead(new ReadOnlySpan(ref registerNumber), buffer); + + // massage the big endian value read from the INA219 unto a ushort. + return BinaryPrimitives.ReadInt16BigEndian(buffer); + } + + /// + /// Write a value to an INA236 register. + /// + /// The register to be written to. + /// The value to be written to the register. + private void WriteRegister(Ina236Register register, ushort value) + { + Span buffer = stackalloc byte[3]; + + // set the first byte of the buffer to the register to be written + buffer[0] = (byte)register; + + // write the value to be written to the second and third bytes in big-endian order. + BinaryPrimitives.WriteUInt16BigEndian(buffer.Slice(1, 2), value); + + // write the value to the register via the I2c Bus. + _i2cDevice.Write(buffer); + } + } +} diff --git a/src/devices/Ina236/Ina236.csproj b/src/devices/Ina236/Ina236.csproj new file mode 100644 index 0000000000..b116cbab81 --- /dev/null +++ b/src/devices/Ina236/Ina236.csproj @@ -0,0 +1,11 @@ + + + $(DefaultBindingTfms) + + false + + + + + + \ No newline at end of file diff --git a/src/devices/Ina236/Ina236.sln b/src/devices/Ina236/Ina236.sln new file mode 100644 index 0000000000..57c4f40ceb --- /dev/null +++ b/src/devices/Ina236/Ina236.sln @@ -0,0 +1,101 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36603.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{0D478BAB-AFEA-4AF1-866C-E3AC32E11C5A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ina236.Samples", "samples\Ina236.Samples.csproj", "{D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ina236", "Ina236.csproj", "{1398DC15-97F0-4048-965A-CCB3D44BFE06}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arduino", "..\Arduino\Arduino.csproj", "{5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ina236.Tests", "tests\Ina236.Tests.csproj", "{7328E5E9-483A-00C5-2E02-D2796B496CD2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "..\Common\Common.csproj", "{9F0601AB-EA31-A20F-1B21-30C901BDC579}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Debug|x64.ActiveCfg = Debug|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Debug|x64.Build.0 = Debug|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Debug|x86.ActiveCfg = Debug|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Debug|x86.Build.0 = Debug|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Release|Any CPU.Build.0 = Release|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Release|x64.ActiveCfg = Release|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Release|x64.Build.0 = Release|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Release|x86.ActiveCfg = Release|Any CPU + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6}.Release|x86.Build.0 = Release|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Debug|x64.ActiveCfg = Debug|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Debug|x64.Build.0 = Debug|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Debug|x86.ActiveCfg = Debug|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Debug|x86.Build.0 = Debug|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Release|Any CPU.Build.0 = Release|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Release|x64.ActiveCfg = Release|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Release|x64.Build.0 = Release|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Release|x86.ActiveCfg = Release|Any CPU + {1398DC15-97F0-4048-965A-CCB3D44BFE06}.Release|x86.Build.0 = Release|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Debug|x64.ActiveCfg = Debug|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Debug|x64.Build.0 = Debug|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Debug|x86.ActiveCfg = Debug|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Debug|x86.Build.0 = Debug|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Release|Any CPU.Build.0 = Release|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Release|x64.ActiveCfg = Release|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Release|x64.Build.0 = Release|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Release|x86.ActiveCfg = Release|Any CPU + {5D91E9F7-12AC-CAB9-87BD-975F0E21D50A}.Release|x86.Build.0 = Release|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Debug|x64.ActiveCfg = Debug|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Debug|x64.Build.0 = Debug|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Debug|x86.ActiveCfg = Debug|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Debug|x86.Build.0 = Debug|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Release|Any CPU.Build.0 = Release|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Release|x64.ActiveCfg = Release|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Release|x64.Build.0 = Release|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Release|x86.ActiveCfg = Release|Any CPU + {7328E5E9-483A-00C5-2E02-D2796B496CD2}.Release|x86.Build.0 = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|x64.ActiveCfg = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|x64.Build.0 = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|x86.ActiveCfg = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|x86.Build.0 = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|Any CPU.Build.0 = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|x64.ActiveCfg = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|x64.Build.0 = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|x86.ActiveCfg = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D9FEFE09-18E7-458A-8ECC-73A8D1E078F6} = {0D478BAB-AFEA-4AF1-866C-E3AC32E11C5A} + {7328E5E9-483A-00C5-2E02-D2796B496CD2} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {34E688F0-222B-4C21-A3C2-B6C54D9D78BF} + EndGlobalSection +EndGlobal diff --git a/src/devices/Ina236/Ina236OperatingMode.cs b/src/devices/Ina236/Ina236OperatingMode.cs new file mode 100644 index 0000000000..42d6627598 --- /dev/null +++ b/src/devices/Ina236/Ina236OperatingMode.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Iot.Device.Adc +{ + /// + /// Current device operating mode + /// + public enum Ina236OperatingMode + { + /// + /// The device is off + /// + Shutdown = 0, + + /// + /// Generate a single measurement of the shunt voltage value, then wait for a command again + /// + SingeShuntVoltage = 0b001, + + /// + /// Generate s single measurement of the shunt voltage value, then wait for a command again + /// + SingleBusVoltage = 0b010, + + /// + /// Generate a single measurement of both bus voltage and shunt voltage, then wait for a command again + /// + SingleShuntAndBusVoltage = 0b011, + + /// + /// Enter shutdown mode + /// + Shutdown2 = 0b100, + + /// + /// Continuously measure the shunt voltage + /// + ContinuousShuntVoltage = 0b101, + + /// + /// Continuously measure the bus voltage + /// + ContinuousBusVoltage = 0b110, + + /// + /// Continuously measure both bus and shut voltages. + /// This is the default setting. + /// + ContinuousShuntAndBusVoltage = 0b111, + + /// + /// A mask field + /// + ModeMask = 0b111 + } +} diff --git a/src/devices/Ina236/Ina236Register.cs b/src/devices/Ina236/Ina236Register.cs new file mode 100644 index 0000000000..6f9622a720 --- /dev/null +++ b/src/devices/Ina236/Ina236Register.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Iot.Device.Adc; + +/// +/// The Ina236 Register map. Note that all registers are 16 bit wide. +/// +internal enum Ina236Register +{ + Configuration = 0, + ShuntVoltage = 1, + BusVoltage = 2, + Power = 3, + Current = 4, + Calibration = 5, + MaskEnable = 6, + AlertLimit = 7, + ManufacturerId = 0x3E, + DeviceId = 0x3F +} diff --git a/src/devices/Ina236/README.md b/src/devices/Ina236/README.md new file mode 100644 index 0000000000..1ad750d57e --- /dev/null +++ b/src/devices/Ina236/README.md @@ -0,0 +1,46 @@ +# INA219 - Bidirectional Current/Power Monitor + +The INA236 is a current shunt and power monitor with an I2C-compatible interface. It is an improved version of the INA219 with a higher accuracy and an extra voltage sensor for the secondary side. The device monitors both shunt voltage drop and bus supply voltage, with programmable conversion times and filtering. A programmable calibration value, combined with an internal multiplier, enables direct readouts of current in amperes. An additional multiplying register calculates power in watts. + +* Senses Bus Voltages from 0 to 26 V +* Reports Current, Voltage, and Power +* 16 Programmable Addresses +* High Accuracy: 0.5% (Maximum) Over Temperature +* Filtering Options +* Calibration Registers +* Two variants available: Address range 0x40-0x43 or 0x60-0x63 + +## Documentation + +* [INA236 Datasheet](http://www.ti.com/lit/ds/symlink/ina236.pdf) + +## Usage + +```csharp +const byte Adafruit_Ina236_I2cAddress = 0x40; + +// create an INA236 device on I2C bus 1 addressing channel 64 +// Known breakouts often have a shunt resistor of 0.008 Ohms and are designed to measure up to 10 Amperes. +using Ina219 device = new Ina236(new I2cConnectionSettings(Adafruit_Ina236_I2cBus, Adafruit_Ina219_I2cAddress), + ElectricResistance.FromMilliohms(8), ElectricCurrent.FromAmperes(10.0)); + +Console.WriteLine("Device initialized. Default settings used:"); +Console.WriteLine($"Operating Mode: {device.OperatingMode}"); +Console.WriteLine($"Number of Samples to average: {device.AverageOverNoSamples}"); +Console.WriteLine($"Bus conversion time: {device.BusConversionTime}us"); +Console.WriteLine($"Shunt conversion time: {device.ShuntConversionTime}us"); + +while (!Console.KeyAvailable) +{ + // write out the current values from the INA219 device. + Console.WriteLine($"Bus Voltage {device.ReadBusVoltage()} Shunt Voltage {device.ReadShuntVoltage().Millivolts}mV Current {device.ReadCurrent()} Power {device.ReadPower()}"); + Thread.Sleep(1000); +} + +``` + +### Notes + +To set up the binding, the shunt resistor value and the maximum expected current need to be provided. Known breakout boards +(e.g. from Adafruit or Joy-It) have a shunt resistor of 0.008 Ohms. With a 10 A load, the voltage drop at the resistor is thus +0.08 V, resulting in a power dissipation of 0.8 Watts. diff --git a/src/devices/Ina236/category.txt b/src/devices/Ina236/category.txt new file mode 100644 index 0000000000..3954b07309 --- /dev/null +++ b/src/devices/Ina236/category.txt @@ -0,0 +1,2 @@ +adc +power diff --git a/src/devices/Ina236/samples/Ina236.Samples.csproj b/src/devices/Ina236/samples/Ina236.Samples.csproj new file mode 100644 index 0000000000..6ab982f9ef --- /dev/null +++ b/src/devices/Ina236/samples/Ina236.Samples.csproj @@ -0,0 +1,10 @@ + + + Exe + $(DefaultSampleTfms) + + + + + + \ No newline at end of file diff --git a/src/devices/Ina236/samples/Program.cs b/src/devices/Ina236/samples/Program.cs new file mode 100644 index 0000000000..620e7ab6fc --- /dev/null +++ b/src/devices/Ina236/samples/Program.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Threading; +using System.Device.I2c; +using Iot.Device; +using Iot.Device.Adc; +using Iot.Device.Arduino; +using UnitsNet; + +using ArduinoBoard board = new ArduinoBoard("COM5", 115200); +using Ina236 device = new(board.CreateI2cDevice(new I2cConnectionSettings(0, 0x40)), ElectricResistance.FromMilliohms(8), + ElectricCurrent.FromAmperes(10.0)); + +Console.WriteLine("Device initialized. Default settings used:"); +Console.WriteLine($"Operating Mode: {device.OperatingMode}"); +Console.WriteLine($"Number of Samples to average: {device.AverageOverNoSamples}"); +Console.WriteLine($"Bus conversion time: {device.BusConversionTime}us"); +Console.WriteLine($"Shunt conversion time: {device.ShuntConversionTime}us"); + +while (!Console.KeyAvailable) +{ + // write out the current values from the INA219 device. + Console.WriteLine($"Bus Voltage {device.ReadBusVoltage()} Shunt Voltage {device.ReadShuntVoltage().Millivolts}mV Current {device.ReadCurrent()} Power {device.ReadPower()}"); + Thread.Sleep(1000); +} diff --git a/src/devices/Ina236/tests/Ina236.Tests.csproj b/src/devices/Ina236/tests/Ina236.Tests.csproj new file mode 100644 index 0000000000..73276062e0 --- /dev/null +++ b/src/devices/Ina236/tests/Ina236.Tests.csproj @@ -0,0 +1,13 @@ + + + + $(DefaultSampleTfms) + false + false + + + + + + + diff --git a/src/devices/Ina236/tests/Ina236Tests.cs b/src/devices/Ina236/tests/Ina236Tests.cs new file mode 100644 index 0000000000..fdf0bb1607 --- /dev/null +++ b/src/devices/Ina236/tests/Ina236Tests.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Device.Gpio; +using System.Device.I2c; +using System.Device.Spi; +using System.Drawing; +using Ina236.Tests; +using Iot.Device.Graphics; +using Moq; +using UnitsNet; +using Xunit; + +namespace Iot.Device.Adc.Tests +{ + public sealed class Ina236Tests : IDisposable + { + private Ina236 _ina236; + private SimulatedIna236 _simulatedIna236; + + public Ina236Tests() + { + _simulatedIna236 = new SimulatedIna236(new I2cConnectionSettings(1, 0x40)); + // Use the setting that corresponds to the example values in the data sheet + _ina236 = new Ina236(_simulatedIna236, ElectricResistance.FromMilliohms(8), ElectricCurrent.FromAmperes(16.384 / 2.0)); + } + + [Fact] + public void InitialValues() + { + Assert.Equal(Ina236OperatingMode.ContinuousShuntAndBusVoltage, _ina236.OperatingMode); + Assert.Equal(1u, _ina236.AverageOverNoSamples); + Assert.Equal(1100, _ina236.BusConversionTime); + Assert.Equal(1100, _ina236.ShuntConversionTime); + } + + [Fact] + public void CheckSetupComplete() + { + int calibrationValue = _simulatedIna236.RegisterMap[5].ReadRegister(); + Assert.Equal(1280, calibrationValue); + } + + [Fact] + public void ReadValues() + { + // Calibration has been set up, so we should get the values mentioned in the data sheet + ElectricPotential voltage = _ina236.ReadBusVoltage(); + Assert.Equal(12.0, voltage.Volts); + + ElectricCurrent current = _ina236.ReadCurrent(); + Assert.Equal(6.0, current.Amperes); + + Power p = _ina236.ReadPower(); + Assert.Equal(72.0m, p.Watts); + } + + public void Dispose() + { + _ina236.Dispose(); + } + } +} diff --git a/src/devices/Ina236/tests/SimulatedIna236.cs b/src/devices/Ina236/tests/SimulatedIna236.cs new file mode 100644 index 0000000000..9e77538074 --- /dev/null +++ b/src/devices/Ina236/tests/SimulatedIna236.cs @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Device.I2c; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Ina236.Tests +{ + internal class SimulatedIna236 : I2cSimulatedDeviceBase + { + public SimulatedIna236(I2cConnectionSettings settings) + : base(settings) + { + RegisterMap.Add(0, new Register(0x4127, ConfigurationRegisterHandler, null)); // 0x4127 is the power-on default of the configuration register + RegisterMap.Add(1, new Register(19200)); // Default values for example from data sheet + RegisterMap.Add(2, new Register(7500)); + RegisterMap.Add(3, new Register(4500)); + RegisterMap.Add(4, new Register(12000)); + RegisterMap.Add(5, new Register()); + RegisterMap.Add(6, new Register()); + RegisterMap.Add(7, new Register()); + // the value is big-endian, but that is taken care of later + RegisterMap.Add(0x3F, new Register(0xA080, DeviceIdentificationRegisterHandler, null)); + } + + private ushort DeviceIdentificationRegisterHandler(ushort arg) + { + // This register is read-only + return 0xA080; + } + + private ushort ConfigurationRegisterHandler(ushort newValue) + { + // When the reset bit is set, set everything to default + if ((newValue & 0x8000) != 0) + { + RegisterMap[5].WriteRegister(0); // Reset the calibration register + return 0x4127; + } + + return newValue; + } + + public override int WriteRead(byte[] inputBuffer, byte[] outputBuffer) + { + if (inputBuffer.Length > 0) + { + CurrentRegister = inputBuffer[0]; + if (inputBuffer.Length >= 3 && RegisterMap.TryGetValue(CurrentRegister, out var register)) + { + ushort reg = BinaryPrimitives.ReadUInt16BigEndian(inputBuffer.AsSpan().Slice(1)); + register.WriteRegister(reg); + } + } + + // All registers of this device are 16 bit, so we need to read that or nothing + if (outputBuffer.Length >= 2 && RegisterMap.TryGetValue(CurrentRegister, out var register2)) + { + ushort ret = (ushort)register2.ReadRegister(); + BinaryPrimitives.WriteUInt16BigEndian(outputBuffer, ret); + } + + return outputBuffer.Length; + } + } +} diff --git a/src/devices/Max31856/Max31856.csproj b/src/devices/Max31856/Max31856.csproj index 5a2122a948..b116cbab81 100644 --- a/src/devices/Max31856/Max31856.csproj +++ b/src/devices/Max31856/Max31856.csproj @@ -3,7 +3,6 @@ $(DefaultBindingTfms) false - 9 diff --git a/src/devices/Mcp23xxx/tests/Mcp23xxx.Tests.csproj b/src/devices/Mcp23xxx/tests/Mcp23xxx.Tests.csproj index 26490ae5f0..5090bd0d06 100644 --- a/src/devices/Mcp23xxx/tests/Mcp23xxx.Tests.csproj +++ b/src/devices/Mcp23xxx/tests/Mcp23xxx.Tests.csproj @@ -1,7 +1,6 @@  $(DefaultTestTfms) - 10 false false diff --git a/src/devices/Mcp25xxx/tests/Mcp25xxx.Tests.csproj b/src/devices/Mcp25xxx/tests/Mcp25xxx.Tests.csproj index 3662eb27ae..3aae4d0e51 100644 --- a/src/devices/Mcp25xxx/tests/Mcp25xxx.Tests.csproj +++ b/src/devices/Mcp25xxx/tests/Mcp25xxx.Tests.csproj @@ -1,7 +1,6 @@  $(DefaultTestTfms) - 9 false false diff --git a/src/devices/Mcp960x/Mcp960x.csproj b/src/devices/Mcp960x/Mcp960x.csproj index 5bfe2f2a17..5240d73261 100644 --- a/src/devices/Mcp960x/Mcp960x.csproj +++ b/src/devices/Mcp960x/Mcp960x.csproj @@ -4,7 +4,6 @@ $(DefaultBindingTfms) false - 9 Iot.Device.Mcp960x Mcp960x diff --git a/src/devices/Nmea0183/tests/Nmea0183.Tests.csproj b/src/devices/Nmea0183/tests/Nmea0183.Tests.csproj index 32a9c7c2d2..1632eaf27a 100644 --- a/src/devices/Nmea0183/tests/Nmea0183.Tests.csproj +++ b/src/devices/Nmea0183/tests/Nmea0183.Tests.csproj @@ -3,7 +3,6 @@ $(DefaultTestTfms) false - latest false Iot.Device.Nmea0183.Tests diff --git a/src/devices/Pcx857x/tests/Pcx857x.Tests.csproj b/src/devices/Pcx857x/tests/Pcx857x.Tests.csproj index cf45e32d2f..271f9639c1 100644 --- a/src/devices/Pcx857x/tests/Pcx857x.Tests.csproj +++ b/src/devices/Pcx857x/tests/Pcx857x.Tests.csproj @@ -1,7 +1,6 @@  $(DefaultTestTfms) - 10 false false diff --git a/src/devices/Rtc/tests/Rtc.Tests.csproj b/src/devices/Rtc/tests/Rtc.Tests.csproj index 4c8bec1f3b..e4d7b250c8 100644 --- a/src/devices/Rtc/tests/Rtc.Tests.csproj +++ b/src/devices/Rtc/tests/Rtc.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultTestTfms) - 9 false false diff --git a/src/devices/Seatalk1/Seatalk1.csproj b/src/devices/Seatalk1/Seatalk1.csproj index 3d5d94dcd9..57b2854ea5 100644 --- a/src/devices/Seatalk1/Seatalk1.csproj +++ b/src/devices/Seatalk1/Seatalk1.csproj @@ -4,7 +4,6 @@ $(DefaultBindingTfms) false - 9 Iot.Device.Seatalk1 diff --git a/src/devices/Seatalk1/tests/Seatalk1.Tests.csproj b/src/devices/Seatalk1/tests/Seatalk1.Tests.csproj index 0e08b4d22b..cd05aeda48 100644 --- a/src/devices/Seatalk1/tests/Seatalk1.Tests.csproj +++ b/src/devices/Seatalk1/tests/Seatalk1.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultSampleTfms) - 10 false false Iot.Device.Tests.Seatalk1 diff --git a/src/devices/SensorHub/SensorHub.csproj b/src/devices/SensorHub/SensorHub.csproj index 38aedfcbc6..a5e1526ca4 100644 --- a/src/devices/SensorHub/SensorHub.csproj +++ b/src/devices/SensorHub/SensorHub.csproj @@ -3,7 +3,6 @@ $(DefaultBindingTfms) false - 9 diff --git a/src/devices/SensorHub/tests/SensorHub.Tests.csproj b/src/devices/SensorHub/tests/SensorHub.Tests.csproj index fc0f51a69d..3121b97fb2 100644 --- a/src/devices/SensorHub/tests/SensorHub.Tests.csproj +++ b/src/devices/SensorHub/tests/SensorHub.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultTestTfms) - 9 false false diff --git a/src/devices/ServoMotor/tests/ServoMotor.Tests.csproj b/src/devices/ServoMotor/tests/ServoMotor.Tests.csproj index 89ff325308..0d005155e1 100644 --- a/src/devices/ServoMotor/tests/ServoMotor.Tests.csproj +++ b/src/devices/ServoMotor/tests/ServoMotor.Tests.csproj @@ -1,7 +1,6 @@  $(DefaultTestTfms) - 9 false false diff --git a/src/devices/SkiaSharpAdapter/SkiaSharpAdapter.csproj b/src/devices/SkiaSharpAdapter/SkiaSharpAdapter.csproj index 28f396fe29..be5295e140 100644 --- a/src/devices/SkiaSharpAdapter/SkiaSharpAdapter.csproj +++ b/src/devices/SkiaSharpAdapter/SkiaSharpAdapter.csproj @@ -4,7 +4,6 @@ $(DefaultBindingTfms) false - latest Iot.Device.Graphics.SkiaSharpAdapter True diff --git a/src/devices/Ssd13xx/samples/spi/Ssd1309.Spi.Samples/Ssd1309.Spi.Samples.csproj b/src/devices/Ssd13xx/samples/spi/Ssd1309.Spi.Samples/Ssd1309.Spi.Samples.csproj index f2521524fa..61928a3f66 100644 --- a/src/devices/Ssd13xx/samples/spi/Ssd1309.Spi.Samples/Ssd1309.Spi.Samples.csproj +++ b/src/devices/Ssd13xx/samples/spi/Ssd1309.Spi.Samples/Ssd1309.Spi.Samples.csproj @@ -5,7 +5,6 @@ $(DefaultSampleTfms) enable enable - 10 diff --git a/src/devices/Ssd13xx/tests/Ssd13xx.Tests.csproj b/src/devices/Ssd13xx/tests/Ssd13xx.Tests.csproj index ccb63cf329..a6f8f50cf5 100644 --- a/src/devices/Ssd13xx/tests/Ssd13xx.Tests.csproj +++ b/src/devices/Ssd13xx/tests/Ssd13xx.Tests.csproj @@ -1,7 +1,6 @@  $(DefaultTestTfms) - 9 false false diff --git a/src/devices/StUsb4500/samples/StUsb4500.Samples.csproj b/src/devices/StUsb4500/samples/StUsb4500.Samples.csproj index a0c6784787..62ac8b4698 100644 --- a/src/devices/StUsb4500/samples/StUsb4500.Samples.csproj +++ b/src/devices/StUsb4500/samples/StUsb4500.Samples.csproj @@ -2,7 +2,6 @@ Exe $(DefaultSampleTfms) - latest diff --git a/src/devices/Tca954x/tests/Tca954x.Tests.csproj b/src/devices/Tca954x/tests/Tca954x.Tests.csproj index 9d92e648b4..5a953f2581 100644 --- a/src/devices/Tca954x/tests/Tca954x.Tests.csproj +++ b/src/devices/Tca954x/tests/Tca954x.Tests.csproj @@ -1,7 +1,6 @@  $(DefaultTestTfms) - 10 false false diff --git a/src/devices/Tca955x/README.md b/src/devices/Tca955x/README.md index 52a4036d27..a6efcdb5c0 100644 --- a/src/devices/Tca955x/README.md +++ b/src/devices/Tca955x/README.md @@ -2,7 +2,7 @@ ## Summary -The TCA955X device family provides 8/16-bit, general purpose I/O expansion for I2C. The devices can be configured with polariy invertion and interrupts. +The TCA955X device family provides 8/16-bit, general purpose I/O expansion for I2C. The devices can be configured with polarity inversion and interrupts. ## Device Family diff --git a/src/devices/Tca955x/Tca955x.csproj b/src/devices/Tca955x/Tca955x.csproj index c50eaf549e..6693497d86 100644 --- a/src/devices/Tca955x/Tca955x.csproj +++ b/src/devices/Tca955x/Tca955x.csproj @@ -4,7 +4,6 @@ $(DefaultBindingTfms) false - 9 diff --git a/src/devices/Tca955x/Tca955x.sln b/src/devices/Tca955x/Tca955x.sln index fd3136b2ac..e227882739 100644 --- a/src/devices/Tca955x/Tca955x.sln +++ b/src/devices/Tca955x/Tca955x.sln @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{AC41B656 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tca955x.Tests", "tests\Tca955x.Tests.csproj", "{F3BCAFCA-A6B8-4530-B435-36FA238D947A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "..\Common\Common.csproj", "{9F0601AB-EA31-A20F-1B21-30C901BDC579}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -59,6 +61,18 @@ Global {F3BCAFCA-A6B8-4530-B435-36FA238D947A}.Release|x64.Build.0 = Release|Any CPU {F3BCAFCA-A6B8-4530-B435-36FA238D947A}.Release|x86.ActiveCfg = Release|Any CPU {F3BCAFCA-A6B8-4530-B435-36FA238D947A}.Release|x86.Build.0 = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|x64.ActiveCfg = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|x64.Build.0 = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|x86.ActiveCfg = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Debug|x86.Build.0 = Debug|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|Any CPU.Build.0 = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|x64.ActiveCfg = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|x64.Build.0 = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|x86.ActiveCfg = Release|Any CPU + {9F0601AB-EA31-A20F-1B21-30C901BDC579}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/devices/Tca955x/tests/MockableI2cDevice.cs b/src/devices/Tca955x/tests/MockableI2cDevice.cs deleted file mode 100644 index 3f15863024..0000000000 --- a/src/devices/Tca955x/tests/MockableI2cDevice.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Device.I2c; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Iot.Device.Tca955x.Tests -{ - /// - /// This class allows mocking of the Read/Write functions of I2cDevice taking Spans - /// - public abstract class MockableI2cDevice : I2cDevice - { - /// - /// These are mockable, operations taking Span<T> are not - /// - /// - public abstract void Read(byte[] data); - public sealed override void Read(Span buffer) - { - byte[] b = new byte[buffer.Length]; - Read(b); - b.CopyTo(buffer); - } - - public abstract void Write(byte[] data); - - public sealed override void Write(ReadOnlySpan buffer) - { - byte[] data = new byte[buffer.Length]; - buffer.CopyTo(data); - Write(data); - } - - public sealed override void WriteRead(ReadOnlySpan writeBuffer, Span readBuffer) - { - Write(writeBuffer); - Read(readBuffer); - } - } -} diff --git a/src/devices/Tca955x/tests/Tca9554Tests.cs b/src/devices/Tca955x/tests/Tca9554Tests.cs index 8f8bcf2fb0..fb61a2ec91 100644 --- a/src/devices/Tca955x/tests/Tca9554Tests.cs +++ b/src/devices/Tca955x/tests/Tca9554Tests.cs @@ -8,33 +8,32 @@ using System.Threading; using Moq; +using Tca955x.Tests; using Xunit; namespace Iot.Device.Tca955x.Tests { public class Tca9554Tests { - private readonly Mock _device; - private readonly Mock _deviceWithBadAddress; + private readonly Tca955xSimulatedDevice _device; + private readonly Mock _deviceWithBadAddress; private readonly GpioController _controller; private readonly Mock _driver; public Tca9554Tests() { - _device = new Mock(MockBehavior.Loose); - _deviceWithBadAddress = new Mock(MockBehavior.Loose); - _device.CallBase = true; + _device = new Tca955xSimulatedDevice(new I2cConnectionSettings(0, Tca9554.DefaultI2cAddress)); + _deviceWithBadAddress = new Mock(MockBehavior.Loose, new I2cConnectionSettings(0, Tca9554.DefaultI2cAddress + Tca9554.AddressRange + 1)); + _deviceWithBadAddress.Setup(x => x.ConnectionSettings).CallBase(); _driver = new Mock(); _driver.CallBase = true; _controller = new GpioController(_driver.Object); - _device.Setup(x => x.ConnectionSettings).Returns(new I2cConnectionSettings(0, Tca9554.DefaultI2cAddress)); - _deviceWithBadAddress.Setup(x => x.ConnectionSettings).Returns(new I2cConnectionSettings(0, Tca9554.DefaultI2cAddress + Tca9554.AddressRange + 1)); } [Fact] public void CreateWithInterrupt() { - var testee = new Tca9554(_device.Object, 10, _controller); + var testee = new Tca9554(_device, 10, _controller); } [Fact] @@ -46,22 +45,13 @@ public void CreateWithBadAddress() [Fact] public void CreateWithoutInterrupt() { - var testee = new Tca9554(_device.Object, -1); + var testee = new Tca9554(_device, -1); } [Fact] public void TestRead() { - _device.Setup(x => x.Write(new byte[1] - { - 0 - })); - _device.Setup(x => x.Read(It.IsAny())).Callback((byte[] b) => - { - b[0] = 1; - }); - - var testee = new Tca9554(_device.Object, -1); + var testee = new Tca9554(_device, -1); var tcaController = new GpioController(testee); Assert.Equal(8, tcaController.PinCount); GpioPin pin0 = tcaController.OpenPin(0); @@ -78,7 +68,7 @@ public void InterruptCallbackIsInvokedOnPinChange() { // Arrange var interruptPin = 10; - var testee = new Tca9554(_device.Object, interruptPin, _controller); + var testee = new Tca9554(_device, interruptPin, _controller); var tcaController = new GpioController(testee); tcaController.OpenPin(1, PinMode.Input); bool callbackInvoked = false; @@ -92,23 +82,15 @@ void Callback(object sender, PinValueChangedEventArgs args) mre.Set(); } - // Change the device setup to simulate pin1 as high - _device.Setup(x => x.Read(It.IsAny())).Callback((byte[] b) => - { - b[0] = 0x02; - }); + _device.SetPinState(1, PinValue.High); // Register callback for rising edge tcaController.RegisterCallbackForPinValueChangedEvent(1, PinEventTypes.Falling, Callback); // Change the device setup to simulate pin1 as low. - _device.Setup(x => x.Read(It.IsAny())).Callback((byte[] b) => - { - b[0] = 0x00; - }); - + _device.SetPinState(1, PinValue.Low); // Act - // Simulate the hardware int pin pin change using the _controller mock + // Simulate the hardware int pin change using the _controller mock _driver.Object.FireEventHandler(interruptPin, PinEventTypes.Rising); mre.Wait(2000); // Wait for the callback to be invoked @@ -122,7 +104,7 @@ void Callback(object sender, PinValueChangedEventArgs args) [Fact] public void TestReadOfIllegalPinThrows() { - var testee = new Tca9554(_device.Object, -1); + var testee = new Tca9554(_device, -1); var tcaController = new GpioController(testee); Assert.Equal(8, tcaController.PinCount); GpioPin pin0 = tcaController.OpenPin(0); @@ -136,12 +118,12 @@ public void CanNotConstructIfInterruptConfiguredIncorrectly() { Assert.Throws(() => { - var testee = new Tca9554(_device.Object, -1, _controller); + var testee = new Tca9554(_device, -1, _controller); }); Assert.Throws(() => { - var testee = new Tca9554(_device.Object, 2); + var testee = new Tca9554(_device, 2); }); } diff --git a/src/devices/Tca955x/tests/Tca9555Tests.cs b/src/devices/Tca955x/tests/Tca9555Tests.cs index f04943dd1d..dfc80d94e8 100644 --- a/src/devices/Tca955x/tests/Tca9555Tests.cs +++ b/src/devices/Tca955x/tests/Tca9555Tests.cs @@ -6,67 +6,57 @@ using System.Device.Gpio.Tests; using System.Device.I2c; using Moq; +using Tca955x.Tests; using Xunit; namespace Iot.Device.Tca955x.Tests { public class Tca9555Tests { - private readonly Mock _device; + private readonly Tca955xSimulatedDevice _device; private readonly GpioController _controller; private readonly Mock _driver; public Tca9555Tests() { - _device = new Mock(MockBehavior.Loose); - _device.CallBase = true; + _device = new Tca955xSimulatedDevice(new I2cConnectionSettings(0, Tca9554.DefaultI2cAddress)); _driver = new Mock(); _controller = new GpioController(_driver.Object); - _device.Setup(x => x.ConnectionSettings).Returns(new I2cConnectionSettings(0, Tca9554.DefaultI2cAddress)); } [Fact] public void CreateWithInterrupt() { - var testee = new Tca9555(_device.Object, 10, _controller); + var testee = new Tca9555(_device, 10, _controller); Assert.NotNull(testee); } [Fact] public void CreateWithoutInterrupt() { - var testee = new Tca9554(_device.Object, -1); + var testee = new Tca9554(_device, -1); Assert.NotNull(testee); } [Fact] public void TestRead() { - _device.Setup(x => x.Write(new byte[1] - { - 0 - })); - _device.Setup(x => x.Read(It.IsAny())).Callback((byte[] b) => - { - b[0] = 1; - }); - - var testee = new Tca9555(_device.Object, -1); + var testee = new Tca9555(_device, -1); var tcaController = new GpioController(testee); Assert.Equal(16, tcaController.PinCount); - GpioPin pin8 = tcaController.OpenPin(8); - Assert.NotNull(pin8); - Assert.True(tcaController.IsPinOpen(8)); - var value = pin8.Read(); + GpioPin pin0 = tcaController.OpenPin(0); + Assert.NotNull(pin0); + Assert.True(tcaController.IsPinOpen(0)); + var value = pin0.Read(); Assert.Equal(PinValue.High, value); - pin8.Dispose(); + pin0.Dispose(); Assert.False(tcaController.IsPinOpen(8)); } [Fact] public void TestReadOfIllegalPinThrows() { - var testee = new Tca9554(_device.Object, -1); + var testee = new Tca9554(_device, -1); var tcaController = new GpioController(testee); Assert.Equal(8, tcaController.PinCount); GpioPin pin0 = tcaController.OpenPin(0); diff --git a/src/devices/Tca955x/tests/Tca955x.Tests.csproj b/src/devices/Tca955x/tests/Tca955x.Tests.csproj index 5f1017feee..82e14bea6a 100644 --- a/src/devices/Tca955x/tests/Tca955x.Tests.csproj +++ b/src/devices/Tca955x/tests/Tca955x.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultSampleTfms) - 10 false false diff --git a/src/devices/Tca955x/tests/Tca955xSimulatedDevice.cs b/src/devices/Tca955x/tests/Tca955xSimulatedDevice.cs new file mode 100644 index 0000000000..fc62e33c83 --- /dev/null +++ b/src/devices/Tca955x/tests/Tca955xSimulatedDevice.cs @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Device.Gpio; +using System.Device.I2c; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tca955x.Tests +{ + internal class Tca955xSimulatedDevice : I2cSimulatedDeviceBase + { + private Register _register0; // pin register 0 + private Register _register2; // polarity inversion register + private Register _register3; // Configuration Register + + public Tca955xSimulatedDevice(I2cConnectionSettings settings) + : base(settings) + { + _register0 = new Register(1); // Pin 0 is high + _register2 = new Register(0); + _register3 = new Register(0); + } + + public void SetPinState(int pin, PinValue value) + { + int bit = 1 << pin; + if (value == PinValue.High) + { + _register0.WriteRegister(_register0.ReadRegister() | bit); + } + else + { + _register0.WriteRegister(_register0.ReadRegister() & ~bit); + } + } + + public override int WriteRead(byte[] inputBuffer, byte[] outputBuffer) + { + if (inputBuffer.Length >= 1) + { + CurrentRegister = inputBuffer[0]; + } + + if (CurrentRegister == 0) + { + outputBuffer[0] = _register0.Value; + return 1; + } + + if (CurrentRegister == 2) + { + if (inputBuffer.Length > 1) + { + _register2.Value = inputBuffer[1]; + } + + if (outputBuffer.Length > 0) + { + outputBuffer[0] = _register2.Value; + return 1; + } + } + + if (CurrentRegister == 3) + { + if (inputBuffer.Length > 1) + { + _register3.Value = inputBuffer[1]; + } + + if (outputBuffer.Length > 0) + { + outputBuffer[0] = _register3.Value; + return 1; + } + } + + return 0; + } + } +} diff --git a/src/devices/Tm16xx/Tm16xx.csproj b/src/devices/Tm16xx/Tm16xx.csproj index 2105b00edc..b3c06cae0a 100644 --- a/src/devices/Tm16xx/Tm16xx.csproj +++ b/src/devices/Tm16xx/Tm16xx.csproj @@ -3,7 +3,6 @@ $(DefaultBindingTfms) false - latest diff --git a/src/devices/Ws28xx/samples/LEDStripSample/LEDStripSample.csproj b/src/devices/Ws28xx/samples/LEDStripSample/LEDStripSample.csproj index abcff228e8..e9cb782b79 100644 --- a/src/devices/Ws28xx/samples/LEDStripSample/LEDStripSample.csproj +++ b/src/devices/Ws28xx/samples/LEDStripSample/LEDStripSample.csproj @@ -5,7 +5,6 @@ $(DefaultSampleTfms) enable enable - 10.0 diff --git a/tools/ArduinoCsCompiler/ArduinoCsCompiler.csproj b/tools/ArduinoCsCompiler/ArduinoCsCompiler.csproj index 4f8d22680a..c2820c1882 100644 --- a/tools/ArduinoCsCompiler/ArduinoCsCompiler.csproj +++ b/tools/ArduinoCsCompiler/ArduinoCsCompiler.csproj @@ -3,7 +3,6 @@ Library net8.0 - latest Debug;Release The .NET Foundation The .NET Foundation diff --git a/tools/ArduinoCsCompiler/Frontend/Frontend.csproj b/tools/ArduinoCsCompiler/Frontend/Frontend.csproj index de00788cb8..db9f3e181d 100644 --- a/tools/ArduinoCsCompiler/Frontend/Frontend.csproj +++ b/tools/ArduinoCsCompiler/Frontend/Frontend.csproj @@ -15,7 +15,6 @@ True false - latest True dotnet-acs ..\..\..\artifacts\packages\$(Configuration)\Shipping diff --git a/tools/ArduinoCsCompiler/tests/ArduinoCsCompiler.Tests.csproj b/tools/ArduinoCsCompiler/tests/ArduinoCsCompiler.Tests.csproj index f25144ec00..9e57d36010 100644 --- a/tools/ArduinoCsCompiler/tests/ArduinoCsCompiler.Tests.csproj +++ b/tools/ArduinoCsCompiler/tests/ArduinoCsCompiler.Tests.csproj @@ -3,7 +3,6 @@ net8.0 false - latest false requires!=hardware diff --git a/tools/DevicesApiTester/DeviceApiTester.csproj b/tools/DevicesApiTester/DeviceApiTester.csproj index 9ce53024ad..a94b1712a1 100644 --- a/tools/DevicesApiTester/DeviceApiTester.csproj +++ b/tools/DevicesApiTester/DeviceApiTester.csproj @@ -3,7 +3,6 @@ Exe net8.0 - 9 Debug;Release The .NET Foundation The .NET Foundation diff --git a/tools/templates/DeviceBindingTemplate/dotnet_new_device-binding_csharp/_DeviceBinding.csproj b/tools/templates/DeviceBindingTemplate/dotnet_new_device-binding_csharp/_DeviceBinding.csproj index 2b43b907b7..92dea8e186 100644 --- a/tools/templates/DeviceBindingTemplate/dotnet_new_device-binding_csharp/_DeviceBinding.csproj +++ b/tools/templates/DeviceBindingTemplate/dotnet_new_device-binding_csharp/_DeviceBinding.csproj @@ -4,7 +4,6 @@ $(DefaultBindingTfms) false - 9 diff --git a/tools/templates/DeviceBindingTemplate/dotnet_new_device-binding_csharp/tests/_DeviceBinding.Tests.csproj b/tools/templates/DeviceBindingTemplate/dotnet_new_device-binding_csharp/tests/_DeviceBinding.Tests.csproj index cc513a3781..dffd9a4feb 100644 --- a/tools/templates/DeviceBindingTemplate/dotnet_new_device-binding_csharp/tests/_DeviceBinding.Tests.csproj +++ b/tools/templates/DeviceBindingTemplate/dotnet_new_device-binding_csharp/tests/_DeviceBinding.Tests.csproj @@ -2,7 +2,6 @@ $(DefaultSampleTfms) - 10 false false