diff --git a/examples/SharpBrick.PoweredUp.Examples/ExampleRampUp.cs b/examples/SharpBrick.PoweredUp.Examples/ExampleRampUp.cs new file mode 100644 index 0000000..70210a2 --- /dev/null +++ b/examples/SharpBrick.PoweredUp.Examples/ExampleRampUp.cs @@ -0,0 +1,50 @@ +using System.Diagnostics; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using SharpBrick.PoweredUp; +using SharpBrick.PoweredUp.Functions; + +namespace Example +{ + public class ExampleRampUp : BaseExample + { + public override async Task ExecuteAsync() + { + using (var technicMediumHub = Host.FindByType()) + { + var stopWatch = new Stopwatch(); + + var motor = technicMediumHub.A.GetDevice(); + + // ramp up with linear speed + var rampUp = ServiceProvider.GetService(); + + await technicMediumHub.RgbLight.SetRgbColorNoAsync(PoweredUpColor.Red); + + stopWatch.Start(); + await rampUp.ExecuteAsync(motor, 20, 100, 40, 5_000); + var redPhase = stopWatch.ElapsedMilliseconds; + + await technicMediumHub.RgbLight.SetRgbColorNoAsync(PoweredUpColor.Green); + + await Task.Delay(2_000); + + await technicMediumHub.RgbLight.SetRgbColorNoAsync(PoweredUpColor.Orange); + + // ramp down with linear speed + var rampDown = ServiceProvider.GetService(); + + var beforeOrangePhase = stopWatch.ElapsedMilliseconds; + await rampDown.ExecuteAsync(motor, 100, 0, 100, 10_000); + var orangePhase = stopWatch.ElapsedMilliseconds - beforeOrangePhase; + stopWatch.Stop(); + + await technicMediumHub.SwitchOffAsync(); + + // time delays (parameter) + 100s of BLE messages async/await ops + Log.LogInformation($"Red Phase: {redPhase}ms; Orange Phase: {orangePhase}ms"); + } + } + } +} \ No newline at end of file diff --git a/examples/SharpBrick.PoweredUp.Examples/Program.cs b/examples/SharpBrick.PoweredUp.Examples/Program.cs index 5b7fd17..7ecccad 100644 --- a/examples/SharpBrick.PoweredUp.Examples/Program.cs +++ b/examples/SharpBrick.PoweredUp.Examples/Program.cs @@ -32,7 +32,8 @@ static async Task Main(string[] args) //example = new Example.ExampleSetHubProperty(); //example = new Example.ExampleHubPropertyObserving(); //example = new Example.ExampleDiscoverByType(); - example = new Example.ExampleCalibrationSteering(); + //example = new Example.ExampleCalibrationSteering(); + example = new Example.ExampleRampUp(); // NOTE: Examples are programmed object oriented style. Base class implements methods Configure, DiscoverAsync and ExecuteAsync to be overwriten on demand. await example.InitHostAndDiscoverAsync(enableTrace); diff --git a/src/SharpBrick.PoweredUp/Functions/IterativeChange.cs b/src/SharpBrick.PoweredUp/Functions/IterativeChange.cs new file mode 100644 index 0000000..fe7c61a --- /dev/null +++ b/src/SharpBrick.PoweredUp/Functions/IterativeChange.cs @@ -0,0 +1,54 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + +namespace SharpBrick.PoweredUp.Functions +{ + public abstract class IterativeChange + { + private readonly ILogger> _logger; + + protected abstract T Function(int idx); + protected abstract Task ChangeAsync(T value, CancellationTokenSource cts); + + public IterativeChange(ILogger> logger) + { + _logger = logger; + } + + protected async Task IterativeExecuteAsync(int iterations, int delayInMilliseconds, CancellationTokenSource cts = default) + { + _logger.LogInformation($"Start iterative change over {iterations} steps"); + + for (int idx = 0; idx < iterations; idx++) + { + _logger.LogInformation($"+ Iteration: {idx}"); + if (cts?.IsCancellationRequested ?? false) + { + _logger.LogInformation("+ Cancelled (before Actor)"); + + break; + } + + var value = Function(idx); + + _logger.LogInformation($"+ Value: {value}"); + + await ChangeAsync(value, cts); + + if (cts?.IsCancellationRequested ?? false) + { + _logger.LogInformation("+ Cancelled (after Actor)"); + + break; + } + + _logger.LogInformation($"+ Waiting {delayInMilliseconds}ms"); + + await Task.Delay(delayInMilliseconds); + } + + _logger.LogInformation("Finished iterative change"); + } + } +} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/Functions/LinearSpeedChange.cs b/src/SharpBrick.PoweredUp/Functions/LinearSpeedChange.cs new file mode 100644 index 0000000..1489a68 --- /dev/null +++ b/src/SharpBrick.PoweredUp/Functions/LinearSpeedChange.cs @@ -0,0 +1,44 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + +namespace SharpBrick.PoweredUp.Functions +{ + public class LinearSpeedChange : IterativeChange + { + private readonly ILogger _logger; + private TachoMotor _motor; + private sbyte _startSpeed; + + public byte MaxPower { get; set; } = 100; + + public sbyte IterationStep { get; private set; } + + public LinearSpeedChange(ILogger logger) + : base(logger) + { + _logger = logger; + } + + public async Task ExecuteAsync(TachoMotor motor, sbyte startSpeed, sbyte endSpeed, int steps, int milliseconds, CancellationTokenSource cts = default) + { + _logger.LogInformation($"Start execute {nameof(LinearSpeedChange)} ({startSpeed} - {endSpeed} over {steps} steps and {milliseconds}ms)"); + _startSpeed = startSpeed; + _motor = motor ?? throw new ArgumentNullException(nameof(motor)); + + IterationStep = (sbyte)((endSpeed - startSpeed) / steps); + _logger.LogInformation($"+ IterationStep: {IterationStep}"); + + await IterativeExecuteAsync(steps, milliseconds / steps, cts); + + _logger.LogInformation($"Finished {nameof(LinearSpeedChange)} "); + } + + protected override sbyte Function(int idx) + => (sbyte)(_startSpeed + IterationStep * (idx + 1)); + + protected override Task ChangeAsync(sbyte value, CancellationTokenSource cts) + => _motor.StartSpeedAsync(value, MaxPower); + } +} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/IServiceCollectionExtensions.cs b/src/SharpBrick.PoweredUp/IServiceCollectionExtensions.cs index a95094f..0c1817d 100644 --- a/src/SharpBrick.PoweredUp/IServiceCollectionExtensions.cs +++ b/src/SharpBrick.PoweredUp/IServiceCollectionExtensions.cs @@ -26,6 +26,8 @@ public static IServiceCollection AddPoweredUp(this IServiceCollection self) // functions .AddTransient() .AddTransient() - .AddTransient(); + .AddTransient() + .AddTransient() + ; } } \ No newline at end of file