Skip to content

Instantly share code, notes, and snippets.

@ncarandini
Last active November 26, 2018 15:38
Show Gist options
  • Save ncarandini/3406a13fee19dc0a11f1542360c9ed24 to your computer and use it in GitHub Desktop.
Save ncarandini/3406a13fee19dc0a11f1542360c9ed24 to your computer and use it in GitHub Desktop.
[Meadow mocked pseudocode] Cycle hue on onboardLed
// Copyright(c) 2018 Nicolò Carandini (aka TPCWare)
// Content
// ======================================================================================================
// This "not for production code" is just an example on how to run an async task that can be cancelled.
// Moreover, in this example there is an implementation of HSL to RGB color conversion.
// Build and test
// =========================================================================================================
// Run it on LinqPad (https://www.linqpad.net/) or use the code to create a Console app on Visual Studio.
// MIT License
// ======================================================================================================
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/ or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
async Task Main() // C# 7.1 and up
{
var app = new RGBApp();
await app.RunAsync();
}
public class RGBApp : AppBase<F7Micro, RGBApp>
{
protected bool _running;
protected RgbPwmLed onboardLed;
private CancellationTokenSource cts;
public RGBApp()
{
onboardLed = new RgbPwmLed(Pins.OnBoardLEDRed, Pins.OnBoardLEDGreen, Pins.OnBoardLEDBlue);
}
public async override Task RunAsync()
{
// Instantiate the CancellationTokenSource.
cts = new CancellationTokenSource();
// We can cancel immediately with this code, put inside a method that has subsribed an event that is triggered by something (a sensor, a button, ...):
// cts.Cancel();
// Because we don't have such an event, we will set automatic cancellation after some time (5 seconds)
cts.CancelAfter(5000);
await CycleHueOnOnboardLed(cts);
}
private async Task CycleHueOnOnboardLed(CancellationTokenSource cts)
{
int pauseMilliseconds = 18;
// Note that because we are using HSL,
// with lightness = 1 all color will be white regardless of the hue,
// with lightness = 0 all colors will be black.
double lightness = 0.5;
double saturation = 1.0;
try
{
while (true)
{
for (int hue = 0; hue < 360; hue++)
{
cts.Token.ThrowIfCancellationRequested();
onboardLed.SetColorFromHSL(hue, saturation, lightness);
await Task.Delay(pauseMilliseconds);
}
}
}
catch (OperationCanceledException)
{
// Don't throw any exception
// we are here because the task was cancelled
}
catch (Exception e)
{
throw new Exception($"An error occurred: {e.Message}");
}
}
}
// *****************************
// Extension methods
// *****************************
public static class ExtendRgbPwmLed
{
public static void SetColorFromHSL(this RgbPwmLed RgbPwmLed, int hue, double sat, double lum)
{
RgbPwmLed.SetColor(ColorConversion.FromHSL(hue, sat, lum));
}
}
// *****************************
// Utils methods
// *****************************
public static class ColorConversion
{
public static Color FromHSL(int hue, double sat, double lum)
{
Color result;
// Check parameters for value range
if (hue < 0 || hue > 360)
{
throw new ArgumentOutOfRangeException(nameof(hue));
}
if (sat < 0 || sat > 1)
{
throw new ArgumentOutOfRangeException(nameof(sat));
}
if (lum < 0 || lum > 1)
{
throw new ArgumentOutOfRangeException(nameof(lum));
}
// Convert HSL to RGB
double r1, g1, b1;
double m;
try
{
double h1 = hue / 60.0;
double c = (1 - Math.Abs(2 * lum - 1)) * sat;
double x = c * (1 - Math.Abs(h1 % 2 - 1));
m = lum - 0.5 * c;
if (h1 <= 1)
{
r1 = c;
g1 = x;
b1 = 0;
}
else if (h1 <= 2)
{
r1 = x;
g1 = c;
b1 = 0;
}
else if (h1 <= 3)
{
r1 = 0;
g1 = c;
b1 = x;
}
else if (h1 <= 4)
{
r1 = 0;
g1 = x;
b1 = c;
}
else if (h1 <= 5)
{
r1 = x;
g1 = 0;
b1 = c;
}
else
{
r1 = c;
g1 = 0;
b1 = x;
}
result = Color.FromArgb(255, Convert.ToInt32(255 * (r1 + m)), Convert.ToInt32(255 * (g1 + m)), Convert.ToInt32(255 * (b1 + m)));
}
catch (Exception ex)
{
throw new Exception("Convert from HSL to RGB failed", ex);
}
return result;
}
}
// *****************************
// Mocked classes
// *****************************
public class AppBase<TDevice, TApp> where TApp : AppBase<TDevice, TApp>
{
public static TApp Current { get; private set; }
public AppBase()
{
Current = (TApp)this;
}
public virtual Task RunAsync()
{
return Task.Delay(1);
}
}
public class RgbPwmLed
{
private Pins redPin;
private Pins greenPin;
private Pins bluePin;
public RgbPwmLed(Pins redPin, Pins greenPin, Pins bluePin)
{
this.redPin = redPin;
this.greenPin = greenPin;
this.bluePin = bluePin;
}
public void SetColor(Color color)
{
// For test pourpose
Console.WriteLine(color.ToString());
}
}
public class F7Micro
{ }
public enum Pins
{
OnBoardLEDRed = 4,
OnBoardLEDGreen = 7,
OnBoardLEDBlue = 12
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment