Skip to content

Commit

Permalink
Merge pull request #1107 from WildernessLabs/feature/potentiometer
Browse files Browse the repository at this point in the history
Feature/potentiometer
  • Loading branch information
adrianstevens authored Jan 4, 2025
2 parents 1404f60 + b19fdf2 commit fa2da40
Show file tree
Hide file tree
Showing 35 changed files with 607 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ namespace Meadow.Foundation.Sensors;
/// </summary>
public class Potentiometer : IPotentiometer, IDisposable
{
/// <inheritdoc/>
public event EventHandler<IChangeResult<Resistance>>? Changed;

private IAnalogInputPort inputPort;
private Voltage referenceVoltage;
private bool portCreated = false;
private Resistance? oldValue;

/// <summary>
/// Gets whether this instance has been disposed.
Expand All @@ -22,7 +26,7 @@ public class Potentiometer : IPotentiometer, IDisposable
/// <summary>
/// Gets the maximum resistance value of the potentiometer.
/// </summary>
public Resistance MaxResistance { get; }
public Resistance MaxResistance { get; private set; }

/// <summary>
/// Initializes a new instance of the Potentiometer class with default reference voltage.
Expand All @@ -31,9 +35,8 @@ public class Potentiometer : IPotentiometer, IDisposable
/// <param name="maxResistance">The maximum resistance value of the potentiometer.</param>
public Potentiometer(IAnalogInputPort inputPort, Resistance maxResistance)

Check warning on line 36 in Source/Meadow.Foundation.Core/Sensors/Potentiometer/Potentiometer.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field 'inputPort' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.
{
this.inputPort = inputPort;
MaxResistance = maxResistance;
referenceVoltage = inputPort.ReferenceVoltage;
Initialize(inputPort, maxResistance, inputPort.ReferenceVoltage);
portCreated = false;
}

/// <summary>
Expand Down Expand Up @@ -63,6 +66,22 @@ public Potentiometer(IPin inputPin, Resistance maxResistance, Voltage referenceV
portCreated = true;
}

private void Initialize(IAnalogInputPort inputPort, Resistance maxResistance, Voltage refereceVoltage)
{
this.inputPort = inputPort;
MaxResistance = maxResistance;
referenceVoltage = inputPort.ReferenceVoltage;

inputPort.Updated += OnInputPortUpdated;
}

private void OnInputPortUpdated(object sender, IChangeResult<Voltage> e)
{
var newValue = new Resistance(MaxResistance.Ohms * e.New.Volts / referenceVoltage.Volts);
Changed?.Invoke(this, new ChangeResult<Resistance>(newValue, oldValue));
oldValue = newValue;
}

/// <summary>
/// Gets the current resistance value of the potentiometer by reading the analog input.
/// Setting the resistance throws NotSupportedException as potentiometer value can only be changed mechanically.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Meadow.Hardware;

namespace Meadow.Foundation.Sensors;

public class SimulatedDigitalOutputPort : IDigitalOutputPort

Check warning on line 5 in Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalOutputPort.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'SimulatedDigitalOutputPort'
{
private bool state;

public bool InitialState { get; }

Check warning on line 9 in Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalOutputPort.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'SimulatedDigitalOutputPort.InitialState'
public string Name { get; }

Check warning on line 10 in Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalOutputPort.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'SimulatedDigitalOutputPort.Name'

public SimulatedDigitalOutputPort(string name, bool initialState)

Check warning on line 12 in Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalOutputPort.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'SimulatedDigitalOutputPort.SimulatedDigitalOutputPort(string, bool)'
{
Name = name;
InitialState = state = initialState;
}

public virtual bool State

Check warning on line 18 in Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalOutputPort.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'SimulatedDigitalOutputPort.State'
{
get => state;
set
{
state = value;
Resolver.Log.Info($"Output {Name} = {State}");
}
}

public IDigitalChannelInfo? Channel => null;

Check warning on line 28 in Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalOutputPort.cs

View workflow job for this annotation

GitHub Actions / build

Nullability of reference types in return type of 'IDigitalChannelInfo? SimulatedDigitalOutputPort.Channel.get' doesn't match implicitly implemented member 'IDigitalChannelInfo IPort<IDigitalChannelInfo>.Channel.get' (possibly because of nullability attributes).
public IPin? Pin => null;

Check warning on line 29 in Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalOutputPort.cs

View workflow job for this annotation

GitHub Actions / build

Nullability of reference types in return type of 'IPin? SimulatedDigitalOutputPort.Pin.get' doesn't match implicitly implemented member 'IPin IPort<IDigitalChannelInfo>.Pin.get' (possibly because of nullability attributes).

public void Dispose()
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Meadow.Hardware;
using Meadow.Units;

namespace Meadow.Foundation.Sensors;

public class SimulatedDigitalSignalAnalyzer : IDigitalSignalAnalyzer
{
private Frequency frequency;
private double dutyCycle = 0.5;
private ulong count;

public SimulatedDigitalSignalAnalyzer(Frequency frequency)
{
this.frequency = frequency;
}

public void SetDutyCycle(double dutyCycle)
{
this.dutyCycle = dutyCycle;
}

public double GetDutyCycle()
{
return dutyCycle;
}

public void SetFrequency(Frequency frequency)
{
this.frequency = frequency;
}

public Frequency GetFrequency()
{
return frequency;
}

public Frequency GetMeanFrequency()
{
return frequency;
}

public void SetCount(ulong count)
{
this.count = count;
}

public ulong GetCount()
{
return count;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,6 @@

namespace Meadow.Foundation.Sensors;

/*
/// <summary>
/// Represents a simulated tone generator that implements both IToneGenerator and ISimulatedSensor interfaces.
/// </summary>
public class SimulatedToneGenerator : IToneGenerator, ISimulatedSensor
{
}
/// <summary>
/// Represents a simulated RgbPwmLed that implements both IRgbPwmLed and ISimulatedSensor interfaces.
/// </summary>
public class SimulatedRgbPwmLed : IRgbPwmLed, ISimulatedSensor
{
}
/// <summary>
/// Represents a simulated barometric pressure sensor that implements both IBarometricPressureSensor and ISimulatedSensor interfaces.
/// </summary>
public class SimulatedBarometricPressureSensor : IBarometricPressureSensor, ISimulatedSensor
{
}
/// <summary>
/// Represents a simulated gas resistance sensor that implements both IGasResistanceSensor and ISimulatedSensor interfaces.
/// </summary>
public class SimulatedGasResistanceSensor : IGasResistanceSensor, ISimulatedSensor
{
}
*/

/// <summary>
/// A base class for simple simulated single-unit sensors
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Meadow.Peripherals.Sensors;
using Meadow.Units;
using System.Threading.Tasks;

namespace Meadow.Foundation.Sensors;

public class SimulatedHallEffectFlowSensor : IVolumetricFlowSensor
{
private SimulatedDigitalSignalAnalyzer _analyzer;
private double _flowCoefficient;

public SimulatedHallEffectFlowSensor(Frequency simulatedPulseFrequency, double flowCoefficient = 80d)
{
_flowCoefficient = flowCoefficient;
_analyzer = new SimulatedDigitalSignalAnalyzer(simulatedPulseFrequency);
}

public void SetSignalFrequency(Frequency frequency)
{
_analyzer.SetFrequency(frequency);
}

public VolumetricFlow Flow => new VolumetricFlow(
_analyzer.GetFrequency().Hertz / _flowCoefficient,
VolumetricFlow.UnitType.LitersPerMinute);

public Task<VolumetricFlow> Read()
{
return Task.FromResult(Flow);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public class ListBox : MicroLayout
/// Spacing, in pixels, between items
/// </summary>
public int ItemSpacing { get; } = 1;

/// <summary>
/// Spacing, in pixels, between the control left and the left of each item
/// </summary>
public int ItemLeftMargin { get; set; } = 2;

/// <summary>
/// Items to display in the ListBox
/// </summary>
Expand All @@ -53,11 +59,11 @@ public ListBox(int left, int top, int width, int height, IFont font)

private void CreateRowLabels(int rowCount)
{
var y = 0;
var y = 2;
for (var i = 0; i < rowCount; i++)
{
Controls.Add(
new Label(Left, Top + y, this.Width, _rowHeight)
new Label(ItemLeftMargin, y, this.Width, _rowHeight)
{
Font = _font,
TextColor = TextColor,
Expand Down Expand Up @@ -182,6 +188,7 @@ private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEven
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
case NotifyCollectionChangedAction.Replace:
// is the added item visible?
if (e.NewStartingIndex < TopIndex + Controls.Count)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Meadow.Hardware;
using Meadow.Units;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Meadow.Foundation.ICs.DigiPots;

Expand All @@ -20,6 +22,9 @@ public class ResistorArray : IPotentiometer, IRheostat
private Mcp4xxx _parent;
private int _index;
private ISpiCommunications _spiComms;
private EventHandler<IChangeResult<Resistance>>? _changedEvent;
private Timer? _pollTimer;
private Resistance? _lastValue;

/// <inheritdoc/>
public Resistance MaxResistance => _parent.MaxResistance;
Expand All @@ -39,6 +44,35 @@ public Resistance Resistance
}
}

/// <inheritdoc/>
public event EventHandler<IChangeResult<Resistance>>? Changed
{
remove
{
_changedEvent -= value;

if (_changedEvent?.GetInvocationList().Length == 0)
{
_pollTimer?.Dispose();
_pollTimer = null;
}
}
add
{
_changedEvent += value;
if (_pollTimer == null)
{
_pollTimer = new Timer(async (_) =>
{
var r = Resistance;
_changedEvent?.Invoke(this, new ChangeResult<Resistance>(r, _lastValue));
_lastValue = r;
await Task.Delay(500);
});
}
}
}

internal ResistorArray(Mcp4xxx parent, int index, ISpiCommunications spiComms)
{
if (index is < 0 or > 1) throw new ArgumentException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -643,5 +643,11 @@ private PortBank GetPortBankForPin(IPin pin)
}
return PortBank.A;
}

/// <inheritdoc/>
public IDigitalSignalAnalyzer CreateDigitalSignalAnalyzer(IPin pin, bool captureDutyCycle)
{
return new SoftDigitalSignalAnalyzer(pin, captureDutyCycle: captureDutyCycle);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ public void AllOn()
/// <param name="state"><b>True</b> to set the pin state high, <b>False</b> to set it low</param>
protected abstract void SetPinState(IPin pin, bool state);

void WriteUint16(ushort value)
private void WriteUint16(ushort value)
{
Span<byte> buffer = stackalloc byte[2];
buffer[0] = (byte)value;
Expand All @@ -313,6 +313,12 @@ private void InterruptPortChanged(object sender, DigitalPortResult e)
}
}

/// <inheritdoc/>
public IDigitalSignalAnalyzer CreateDigitalSignalAnalyzer(IPin pin, bool captureDutyCycle)
{
return new SoftDigitalSignalAnalyzer(pin, captureDutyCycle: captureDutyCycle);
}

/// <summary>
/// Dispose of the object
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Meadow.Hardware;

namespace Meadow.Peripherals.Sensors.Flow;

/// <summary>
/// Driver for the GR-105 Hall effect water flow sensor.
/// </summary>
/// <remarks>
/// Configures the sensor with its factory calibration values:
/// - Scale factor: 5.5 Hz per L/min
/// </remarks>
public class Gr105 : HallEffectBase
{
/// <summary>
/// Initializes a new instance of the GR-105 flow sensor.
/// </summary>
/// <param name="pin">The digital input pin connected to the sensor's signal line.</param>
public Gr105(IPin pin)
: base(pin, 5.5d)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Meadow.Hardware;

namespace Meadow.Peripherals.Sensors.Flow;

/// <summary>
/// Driver for the GR-201 Hall effect water flow sensor.
/// </summary>
/// <remarks>
/// Configures the sensor with its factory calibration values:
/// - Scale factor: 7.5 Hz per L/min
/// </remarks>
public class Gr201 : HallEffectBase
{
/// <summary>
/// Initializes a new instance of the GR-201 flow sensor.
/// </summary>
/// <param name="pin">The digital input pin connected to the sensor's signal line.</param>
public Gr201(IPin pin)
: base(pin, 7.5d)
{
}
}
Loading

0 comments on commit fa2da40

Please sign in to comment.