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 |  |
| SysFsDriver | C# | System.Device.Gpio 1.3.0 | 2020-02-20 | 692 Hz |  |
@@ -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 |  |
| SysFsDriver | C# | System.Device.Gpio 1.3.0 | 2020-02-22 | 4.27 KHz |  |
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