Skip to content

Commit

Permalink
Merge pull request #161 from SainsburyWellcomeCentre/aeon-foraging
Browse files Browse the repository at this point in the history
Split dispenser state from dispenser UI controller
  • Loading branch information
glopesdev authored Oct 18, 2023
2 parents b1ce707 + fcce272 commit 05db9b0
Show file tree
Hide file tree
Showing 13 changed files with 299 additions and 141 deletions.
2 changes: 1 addition & 1 deletion src/Aeon.Foraging/Aeon.Foraging.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<PackageTags>Bonsai Rx Project Aeon Foraging</PackageTags>
<TargetFramework>net472</TargetFramework>
<VersionPrefix>0.1.0</VersionPrefix>
<VersionSuffix>build231009</VersionSuffix>
<VersionSuffix>build231010</VersionSuffix>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/Aeon.Foraging/Aeon.Foraging.csproj.user
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<ItemGroup>
<Compile Update="DispenserStateControl.cs">
<Compile Update="DispenserEventControl.cs">
<SubType>UserControl</SubType>
</Compile>
</ItemGroup>
Expand Down
28 changes: 28 additions & 0 deletions src/Aeon.Foraging/CreateDispenserEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using Bonsai;

namespace Aeon.Foraging
{
[Description("Create a sequence of dispenser event commands.")]
public class CreateDispenserEvent : Source<DispenserEventArgs>
{
[Description("The number of dispenser units associated with the event command.")]
public int Value { get; set; }

[Description("Specifies the type of dispenser event command to create.")]
public DispenserEventType EventType { get; set; }

public override IObservable<DispenserEventArgs> Generate()
{
return Observable.Return(new DispenserEventArgs(Value, EventType));
}

public IObservable<DispenserEventArgs> Generate<TSource>(IObservable<TSource> source)
{
return source.Select(value => new DispenserEventArgs(Value, EventType));
}
}
}
44 changes: 44 additions & 0 deletions src/Aeon.Foraging/DispenserAccumulate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using Bonsai;

namespace Aeon.Foraging
{
[Combinator]
[Description("Generates a sequence of the estimated number of units in the specified dispenser.")]
public class DispenserAccumulate
{
public IObservable<DispenserState> Process(IObservable<DispenserEventArgs> source)
{
return source.Scan(new DispenserState(), Accumulate);
}

public IObservable<DispenserState> Process(IObservable<DispenserEventArgs> source, IObservable<DispenserState> seed)
{
return seed.Take(1).SelectMany(state => source.Scan(state, Accumulate));
}

static DispenserState Accumulate(DispenserState state, DispenserEventArgs evt)
{
return evt.EventType switch
{
DispenserEventType.Discount => new DispenserState { Count = state.Count - evt.Value },
DispenserEventType.Refill => new DispenserState { Count = state.Count + evt.Value },
DispenserEventType.Reset => new DispenserState { Count = evt.Value },
_ => throw new InvalidOperationException("Invalid dispenser event type."),
};
}
}

public class DispenserState
{
public int Count { get; set; }

public override string ToString()
{
return $"DispenserState(Total: {Count})";
}
}
}
37 changes: 37 additions & 0 deletions src/Aeon.Foraging/DispenserController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Aeon.Acquisition;
using Bonsai;
using Bonsai.Harp;
using System;
using System.ComponentModel;
using System.Reactive.Linq;
using System.Reactive.Subjects;

namespace Aeon.Foraging
{
[DefaultProperty(nameof(Name))]
[TypeVisualizer(typeof(DispenserEventVisualizer))]
[Description("Generates a sequence of event commands for the specified dispenser.")]
public class DispenserController : MetadataSource<DispenserEventArgs>, INamedElement
{
[Description("The name of the dispenser.")]
public string Name { get; set; }

string INamedElement.Name => $"{Name}{nameof(DispenserController)}";

internal BehaviorSubject<DispenserState> State { get; } = new(value: default);

public IObservable<DispenserEventArgs> Process(IObservable<DispenserState> source)
{
return Process().Merge(source
.Do(State).IgnoreElements()
.Cast<DispenserEventArgs>());
}

public IObservable<Timestamped<DispenserEventArgs>> Process(IObservable<DispenserState> source, IObservable<HarpMessage> clockSource)
{
return Process(clockSource).Merge(source
.Do(State).IgnoreElements()
.Cast<Timestamped<DispenserEventArgs>>());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
namespace Aeon.Foraging
{
public class DispenserStateMetadata
public class DispenserEventArgs
{
public DispenserStateMetadata(string name, int value, DispenserEventType eventType)
public DispenserEventArgs(int value, DispenserEventType eventType)
{
Name = name;
Value = value;
EventType = eventType;
}

public string Name { get; }

public int Value { get; }

public DispenserEventType EventType { get; }

public override string ToString()
{
return $"DispenserState({Name}, {EventType}, Total:{Value})";
return $"DispenserEvent({EventType}, Value:{Value})";
}
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@

namespace Aeon.Foraging
{
public partial class DispenserStateControl : UserControl
public partial class DispenserEventControl : UserControl
{
int currentValue;

public DispenserStateControl(DispenserState source)
public DispenserEventControl(DispenserController source)
{
Source = source ?? throw new ArgumentNullException(nameof(source));
InitializeComponent();

var dispenserName = Source.Name;
if (!string.IsNullOrEmpty(dispenserName))
{
dispenserGroupBox.Text = $"{dispenserName} Dispenser";
dispenserGroupBox.Text = $"{dispenserName}";
}
}

public DispenserState Source { get; }
public DispenserController Source { get; }

public int Value
{
Expand All @@ -31,16 +31,24 @@ public int Value
}
}

private void deliverButton_Click(object sender, EventArgs e)
{
OnDispenserEvent(1m, DispenserEventType.Discount);
}

private void refillButton_Click(object sender, EventArgs e)
{
var metadata = new DispenserStateMetadata(Source.Name, (int)refillUpDown.Value, DispenserEventType.Refill);
Source.OnNext(metadata);
OnDispenserEvent(refillUpDown.Value, DispenserEventType.Refill);
}

private void resetButton_Click(object sender, EventArgs e)
{
var delta = (int)refillUpDown.Value - Value;
var metadata = new DispenserStateMetadata(Source.Name, delta, DispenserEventType.Reset);
OnDispenserEvent(refillUpDown.Value, DispenserEventType.Reset);
}

private void OnDispenserEvent(decimal value, DispenserEventType eventType)
{
var metadata = new DispenserEventArgs((int)value, eventType);
Source.OnNext(metadata);
}
}
Expand Down
Loading

0 comments on commit 05db9b0

Please sign in to comment.