未验证 提交 cf3887b5 编写于 作者: O Oliver Japes 提交者: GitHub

Added support for WS2815B (#1800)

* Introduced color mode, added support for WS2815B

* Revamped the sample

* Changed sample

* Fixed namespace

* Updated Readme

* Removed YouTube-Link

* Added copyright headers

* Removed color mode, added derivation of BitmapImageNeo3 for RGB-format

* Added new commented line that shows that the initialization of Ws2815b is identical to the other strips

* Broken up the menu output for better readability

* Moved properties (back) to protected const fields
上级 3ded70bd
......@@ -7,18 +7,19 @@ using Iot.Device.Graphics;
namespace Iot.Device.Ws28xx
{
/// <summary>
/// Special 24bit RGB format for Neo pixel LEDs where each bit is converted to 3 bits.
/// Special 24bit GRB format for Neo pixel LEDs where each bit is converted to 3 bits.
/// A one is converted to 110, a zero is converted to 100.
/// </summary>
internal class BitmapImageNeo3 : BitmapImage
{
private const int BytesPerComponent = 3;
private const int BytesPerPixel = BytesPerComponent * 3;
// The Neo Pixels require a 50us delay (all zeros) after. Since Spi freq is not exactly
// as requested 100us is used here with good practical results. 100us @ 2.4Mbps and 8bit
// data means we have to add 30 bytes of zero padding.
private const int ResetDelayInBytes = 30;
protected const int BytesPerComponent = 3;
protected const int BytesPerPixel = BytesPerComponent * 3;
public BitmapImageNeo3(int width, int height)
: base(new byte[width * height * BytesPerPixel + ResetDelayInBytes], width, height, width * BytesPerPixel)
{
......@@ -38,7 +39,8 @@ namespace Iot.Device.Ws28xx
Data[offset++] = _lookup[c.B * BytesPerComponent + 2];
}
private static readonly byte[] _lookup = new byte[256 * BytesPerComponent];
protected static readonly byte[] _lookup = new byte[256 * BytesPerComponent];
static BitmapImageNeo3()
{
for (int i = 0; i < 256; i++)
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Drawing;
namespace Iot.Device.Ws28xx
{
/// <summary>
/// Special 24bit RGB format for Neo pixel LEDs where each bit is converted to 3 bits.
/// A one is converted to 110, a zero is converted to 100.
/// </summary>
/// <seealso cref="Iot.Device.Ws28xx.BitmapImageNeo3" />
internal class BitmapImageNeo3Rgb : BitmapImageNeo3
{
public BitmapImageNeo3Rgb(int width, int height)
: base(width, height)
{
}
public override void SetPixel(int x, int y, Color c)
{
var offset = y * Stride + x * BytesPerPixel;
Data[offset++] = _lookup[c.R * BytesPerComponent + 0];
Data[offset++] = _lookup[c.R * BytesPerComponent + 1];
Data[offset++] = _lookup[c.R * BytesPerComponent + 2];
Data[offset++] = _lookup[c.G * BytesPerComponent + 0];
Data[offset++] = _lookup[c.G * BytesPerComponent + 1];
Data[offset++] = _lookup[c.G * BytesPerComponent + 2];
Data[offset++] = _lookup[c.B * BytesPerComponent + 0];
Data[offset++] = _lookup[c.B * BytesPerComponent + 1];
Data[offset++] = _lookup[c.B * BytesPerComponent + 2];
}
}
}
......@@ -2,11 +2,12 @@
This binding allows you to update the RGB LEDs on Ws28xx / SK6812 and based strips and matrices.
To see how to use the binding in code, see the [sample](samples/Ws28xx_Samples/Program.cs).
To see how to use the binding in code, see the [sample](samples/LEDStripSample/Program.cs).
## Documentation
* WS2812B: [Datasheet](https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf)
* WS2815B: [Datasheet](http://www.world-semi.com/DownLoadFile/138)
* WS2808: [Datasheet](https://datasheetspdf.com/pdf-file/806051/Worldsemi/WS2801/1)
* SK6812: [Datasheet](https://cdn-shop.adafruit.com/product-files/2757/p2757_SK6812RGBW_REV01.pdf)
* [Neo pixels guide](https://learn.adafruit.com/adafruit-neopixel-uberguide)
......@@ -46,6 +47,7 @@ using SpiDevice spi = SpiDevice.Create(settings);
Ws28xx neo = new Ws2808(spi, count);
// Ws28xx neo = new Ws2812b(spi, Count);
// Ws2815b neo = new Ws2815b(spi, ledCount);
while (true)
{
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Device.Spi;
namespace Iot.Device.Ws28xx
{
/// <summary>
/// Represents WS2815B LED driver
/// </summary>
public class Ws2815b : Ws28xx
{
/// <summary>
/// Constructs Ws2815b instance
/// </summary>
/// <remarks>In contrast to <see cref="Ws2812b"/> this constructor changes the order of the color values.</remarks>
/// <param name="spiDevice">SPI device used for communication with the LED driver</param>
/// <param name="width">Width of the screen or LED strip</param>
/// <param name="height">Height of the screen or LED strip. Defaults to 1 (LED strip).</param>
public Ws2815b(SpiDevice spiDevice, int width, int height = 1)
: base(spiDevice, new BitmapImageNeo3Rgb(width, height))
{
}
}
}

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31729.503
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{B2C3D1C3-4F59-4544-982C-E205F522DF27}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ws28xx.Samples", "samples\Ws28xx_Samples\Ws28xx.Samples.csproj", "{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ws28xx", "Ws28xx.csproj", "{D909238E-13C4-45C4-B044-CCBB08B51647}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sk6812.Samples", "samples\Sk6812_Samples\Sk6812.Samples.csproj", "{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LEDStripSample", "samples\LEDStripSample\LEDStripSample.csproj", "{C76432A3-D59A-44FF-B138-298E7B988615}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
......@@ -21,18 +19,6 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Debug|x64.ActiveCfg = Debug|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Debug|x64.Build.0 = Debug|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Debug|x86.ActiveCfg = Debug|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Debug|x86.Build.0 = Debug|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Release|Any CPU.Build.0 = Release|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Release|x64.ActiveCfg = Release|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Release|x64.Build.0 = Release|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Release|x86.ActiveCfg = Release|Any CPU
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED}.Release|x86.Build.0 = Release|Any CPU
{D909238E-13C4-45C4-B044-CCBB08B51647}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D909238E-13C4-45C4-B044-CCBB08B51647}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D909238E-13C4-45C4-B044-CCBB08B51647}.Debug|x64.ActiveCfg = Debug|Any CPU
......@@ -45,25 +31,24 @@ Global
{D909238E-13C4-45C4-B044-CCBB08B51647}.Release|x64.Build.0 = Release|Any CPU
{D909238E-13C4-45C4-B044-CCBB08B51647}.Release|x86.ActiveCfg = Release|Any CPU
{D909238E-13C4-45C4-B044-CCBB08B51647}.Release|x86.Build.0 = Release|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Debug|x64.ActiveCfg = Debug|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Debug|x64.Build.0 = Debug|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Debug|x86.ActiveCfg = Debug|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Debug|x86.Build.0 = Debug|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Release|Any CPU.Build.0 = Release|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Release|x64.ActiveCfg = Release|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Release|x64.Build.0 = Release|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Release|x86.ActiveCfg = Release|Any CPU
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192}.Release|x86.Build.0 = Release|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Debug|x64.ActiveCfg = Debug|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Debug|x64.Build.0 = Debug|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Debug|x86.ActiveCfg = Debug|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Debug|x86.Build.0 = Debug|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Release|Any CPU.Build.0 = Release|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Release|x64.ActiveCfg = Release|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Release|x64.Build.0 = Release|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Release|x86.ActiveCfg = Release|Any CPU
{C76432A3-D59A-44FF-B138-298E7B988615}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{D97F0DC4-777E-4F1A-BF18-A63DA22707ED} = {B2C3D1C3-4F59-4544-982C-E205F522DF27}
{76D2B9B1-CBDE-445C-BE6D-B5C5C1754192} = {B2C3D1C3-4F59-4544-982C-E205F522DF27}
{C76432A3-D59A-44FF-B138-298E7B988615} = {B2C3D1C3-4F59-4544-982C-E205F522DF27}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F452F127-C7D8-4D14-9484-B23E8F0C3468}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Drawing;
using Iot.Device.Graphics;
using Iot.Device.Ws28xx;
namespace LEDStripSample
{
/// <summary>
/// This type defines several animation examples.
/// </summary>
public class Animations
{
private int _ledCount;
private Ws28xx _ledStrip;
/// <summary>
/// Initializes a new instance of the <see cref="Animations"/> class.
/// </summary>
/// <param name="ledStrip">The led strip.</param>
/// <param name="ledCount">The led count.</param>
public Animations(Ws28xx ledStrip, int ledCount)
{
_ledStrip = ledStrip;
_ledCount = ledCount;
}
/// <summary>
/// Gets or sets a value indicating whether the attached strips supports a separate white LED (warmwhite/coldwhite).
/// </summary>
/// <value>
/// <c>true</c> if [supports separate white]; otherwise, <c>false</c>.
/// </value>
public virtual bool SupportsSeparateWhite { get; set; } = false;
/// <summary>
/// Wipes the selected color.
/// </summary>
/// <param name="color">The color.</param>
public void ColorWipe(Color color)
{
var img = _ledStrip.Image;
for (var i = 0; i < _ledCount; i++)
{
img.SetPixel(i, 0, color);
_ledStrip.Update();
Thread.Sleep(25);
}
}
/// <summary>
/// Filters the color in regards of the .
/// </summary>
/// <param name="source">The source.</param>
/// <returns></returns>
public Color FilterColor(Color source)
{
return SupportsSeparateWhite ? Color.FromArgb(0, source.R, source.G, source.B) : source;
}
/// <summary>
/// Animation similar to "Knight Rider".
/// </summary>
/// <param name="token">The token.</param>
public async void KnightRider(CancellationToken token)
{
var img = _ledStrip.Image;
var downDirection = false;
var beamLength = 15;
var index = 0;
while (!token.IsCancellationRequested)
{
for (int i = 0; i < _ledCount; i++)
{
img.SetPixel(i, 0, Color.FromArgb(0, 0, 0, 0));
}
if (downDirection)
{
for (int i = 0; i <= beamLength; i++)
{
if (index + i < _ledCount && index + i >= 0)
{
var redValue = (beamLength - i) * (255 / (beamLength + 1));
img.SetPixel(index + i, 0, Color.FromArgb(0, redValue, 0, 0));
}
}
index--;
if (index < -beamLength)
{
downDirection = false;
index = 0;
}
}
else
{
for (int i = beamLength - 1; i >= 0; i--)
{
if (index - i >= 0 && index - i < _ledCount)
{
var redValue = (beamLength - i) * (255 / (beamLength + 1));
img.SetPixel(index - i, 0, Color.FromArgb(0, redValue, 0, 0));
}
}
index++;
if (index - beamLength >= _ledCount)
{
downDirection = true;
index = _ledCount - 1;
}
}
_ledStrip.Update();
await Task.Delay(10).ConfigureAwait(false);
}
}
/// <summary>
/// Rainbows the specified count.
/// </summary>
/// <param name="token">The token.</param>
public void Rainbow(CancellationToken token)
{
BitmapImage img = _ledStrip.Image;
while (!token.IsCancellationRequested)
{
for (var i = 0; i < 255; i++)
{
if (token.IsCancellationRequested)
{
break;
}
for (var j = 0; j < _ledCount; j++)
{
if (token.IsCancellationRequested)
{
break;
}
img.SetPixel(j, 0, Wheel((i + j) & 255));
}
_ledStrip.Update();
Thread.Sleep(25);
}
}
}
/// <summary>
/// Sets the color of the entire strip.
/// </summary>
/// <param name="color">The color.</param>
/// <param name="count">The count.</param>
public void SetColor(Color color, int count)
{
BitmapImage img = _ledStrip.Image;
for (var i = 0; i < count; i++)
{
img.SetPixel(i, 0, color);
}
_ledStrip.Update();
}
/// <summary>
/// Sets the white value using a percentag.
/// </summary>
/// <param name="colorPercentage">The color percentage.</param>
/// <param name="separateWhite">if set to <c>true</c> [separate white].</param>
public void SetWhiteValue(float colorPercentage, bool separateWhite = false)
{
var color = Color.FromArgb(separateWhite ? (int)(255 * colorPercentage) : 0, !separateWhite ? (int)(255 * colorPercentage) : 0, !separateWhite ? (int)(255 * colorPercentage) : 0, !separateWhite ? (int)(255 * colorPercentage) : 0);
SetColor(color, _ledCount);
}
/// <summary>
/// Switches the LEDs off.
/// </summary>
public void SwitchOffLeds()
{
var img = _ledStrip.Image;
img.Clear();
_ledStrip.Update();
}
/// <summary>
/// Theatre Chase animation.
/// </summary>
/// <param name="color">The color.</param>
/// <param name="blankColor">Color of the blank.</param>
/// <param name="token">The token.</param>
public void TheatreChase(Color color, Color blankColor, CancellationToken token)
{
BitmapImage img = _ledStrip.Image;
while (!token.IsCancellationRequested)
{
for (var j = 0; j < 3; j++)
{
for (var k = 0; k < _ledCount; k += 3)
{
img.SetPixel(j + k, 0, color);
}
_ledStrip.Update();
Thread.Sleep(100);
for (var k = 0; k < _ledCount; k += 3)
{
img.SetPixel(j + k, 0, blankColor);
}
}
}
}
private Color Wheel(int position)
{
if (position < 85)
{
return Color.FromArgb(0, position * 3, 255 - position * 3, 0);
}
else if (position < 170)
{
position -= 85;
return Color.FromArgb(0, 255 - position * 3, 0, position * 3);
}
else
{
position -= 170;
return Color.FromArgb(0, 0, position * 3, 255 - position * 3);
}
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>10.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../Ws28xx.csproj" />
<ProjectReference Include="../../Ws28xx.csproj" />
</ItemGroup>
</Project>
\ No newline at end of file
</Project>
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LEDStripSample
{
internal enum MenuId
{
Root,
WhiteLevel,
TheatreChase,
Wipe,
Special,
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Device.Spi;
using System.Drawing;
using Iot.Device.Ws28xx;
using LEDStripSample;
Console.WriteLine("Attach debugger if you want to, press any key to continue");
Console.ReadKey();
Console.Clear();
SpiConnectionSettings settings = new(0, 0)
{
ClockFrequency = 2_400_000,
Mode = SpiMode.Mode0,
DataBitLength = 8
};
using SpiDevice spi = SpiDevice.Create(settings);
var ledCount = -1;
MenuId menuId = MenuId.Root;
Animations? effects = null;
while (ledCount == -1)
{
Console.Write("Number of LEDs (0 to exit): ");
var input = Console.ReadLine();
if (int.TryParse(input, out ledCount))
{
break;
}
}
if (ledCount == 0)
{
return;
}
while (true)
{
Console.WriteLine("1: WS2812b");
Console.WriteLine("2: WS2815b");
Console.WriteLine("3: SK68012");
Console.WriteLine("0: Exit");
Console.Write("Type of Strip: ");
var ledType = Console.ReadLine()!.Trim();
switch (ledType)
{
case "0":
return;
case "1":
effects = new Animations(new Ws2812b(spi, ledCount), ledCount);
break;
case "2":
effects = new Animations(new Ws2815b(spi, ledCount), ledCount);
break;
case "3":
effects = new Animations(new Sk6812(spi, ledCount), ledCount) { SupportsSeparateWhite = true };
break;
default:
Console.WriteLine("Unsupported selection.");
break;
}
if (effects != null)
{
break;
}
}
var isActive = true;
effects!.SwitchOffLeds();
var colorPercentage = 1.0f;
while (isActive)
{
DrawMenu();
}
Console.WriteLine("Exit application.");
void DrawMenu()
{
Console.Clear();
switch (menuId)
{
case MenuId.Root:
isActive = DrawMainMenu();
break;
case MenuId.WhiteLevel:
DrawWhiteLevelMenu();
break;
case MenuId.TheatreChase:
DrawTheatreChaseMenu();
break;
case MenuId.Wipe:
DrawWipeMenu();
break;
case MenuId.Special:
DrawSpecialMenu();
break;
}
}
void DrawSpecialMenu()
{
Console.WriteLine("1. Knight Rider");
Console.WriteLine("0: Back");
Console.Write("Selection: ");
var choice = Console.ReadLine();
switch (choice)
{
case "0":
menuId = MenuId.Root;
break;
case "1":
StartKnightRider();
break;
default:
Console.WriteLine("Unknown Selection. Any key to continue.");
Console.ReadKey();
break;
}
}
void DrawWipeMenu()
{
Console.WriteLine("1. Wipe black");
Console.WriteLine("2. Wipe red");
Console.WriteLine("3. Wipe green");
Console.WriteLine("4. Wipe blue");
Console.WriteLine("5. Wipe yellow");
Console.WriteLine("6. Wipe turqoise");
Console.WriteLine("7. Wipe purple");
Console.WriteLine("8. Wipe cold white");
if (effects.SupportsSeparateWhite)
{
Console.WriteLine("9: Separate white");
}
Console.WriteLine("0: Back");
Console.Write("Selection: ");
var choice = Console.ReadLine();
switch (choice)
{
case "0":
menuId = MenuId.Root;
break;
case "1":
effects.ColorWipe(effects.FilterColor(Color.Black));
break;
case "2":
effects.ColorWipe(effects.FilterColor(Color.Red));
break;
case "3":
effects.ColorWipe(effects.FilterColor(Color.Green));
break;
case "4":
effects.ColorWipe(effects.FilterColor(Color.Blue));
break;
case "5":
effects.ColorWipe(effects.FilterColor(Color.Yellow));
break;
case "6":
effects.ColorWipe(effects.FilterColor(Color.Turquoise));
break;
case "7":
effects.ColorWipe(effects.FilterColor(Color.Purple));
break;
case "8":
effects.ColorWipe(effects.FilterColor(Color.White));
break;
case "9":
effects.ColorWipe(Color.FromArgb(255, 0, 0, 0));
break;
default:
Console.WriteLine("Unbekannter Eintrag. Beliebige Taste zum fortfahren.");
Console.ReadKey();
break;
}
}
void DrawTheatreChaseMenu()
{
Console.WriteLine("1: All LED off");
Console.WriteLine("2: Chase in red");
Console.WriteLine("3: Chase in green");
Console.WriteLine("4: Chase in blue");
Console.WriteLine("5: Christmas Chase");
if (effects.SupportsSeparateWhite)
{
Console.WriteLine("6: White Chase");
}
Console.WriteLine("0: Back");
Console.Write("Selection: ");
var choice = Console.ReadLine();
switch (choice)
{
case "0":
menuId = MenuId.Root;
break;
case "1":
effects.SwitchOffLeds();
break;
case "2":
StartChase(effects.FilterColor(Color.Red), Color.FromArgb(0, 0, 0, 0));
break;
case "3":
StartChase(effects.FilterColor(Color.Green), Color.FromArgb(0, 0, 0, 0));
break;
case "4":
StartChase(effects.FilterColor(Color.Blue), Color.FromArgb(0, 0, 0, 0));
break;
case "5":
StartChase(effects.FilterColor(Color.Red), effects.FilterColor(Color.Green));
break;
case "6":
StartChase(Color.FromArgb(255, 0, 0, 0), Color.FromArgb(0, 0, 0, 0));
break;
default:
Console.WriteLine("Unbekannter Eintrag. Beliebige Taste zum fortfahren.");
Console.ReadKey();
break;
}
}
bool DrawMainMenu()
{
Console.WriteLine("1: All LED off");
Console.WriteLine("2: All LED to white (percentual)");
Console.WriteLine("3: Rainbow");
Console.WriteLine("4: TheatreChase");
Console.WriteLine("5: Wipe");
Console.WriteLine("6: Special");
Console.WriteLine("0: Back");
Console.Write("Selection: ");
var choice = Console.ReadLine();
var keepActive = true;
switch (choice)
{
case "0":
keepActive = false;
break;
case "1":
effects.SwitchOffLeds();
keepActive = true;
break;
case "2":
keepActive = true;
menuId = MenuId.WhiteLevel;
break;
case "3":
StartRainbow();
break;
case "4":
menuId = MenuId.TheatreChase;
break;
case "5":
menuId = MenuId.Wipe;
break;
case "6":
menuId = MenuId.Special;
break;
default:
Console.WriteLine("Unknown Selection. Any key to continue.");
Console.ReadKey();
break;
}
return keepActive;
}
void DrawWhiteLevelMenu()
{
Console.WriteLine($"1: Change percentag (currently: {colorPercentage * 100}%)");
Console.WriteLine("2: LEDs white (RGB)");
if (effects.SupportsSeparateWhite)
{
Console.WriteLine("3: Separate White");
}
Console.WriteLine("0: Back");
Console.Write("Selection: ");
var choice = Console.ReadLine();
switch (choice)
{
case "0":
menuId = MenuId.Root;
break;
case "1":
RequestPercentage();
break;
case "2":
effects.SetWhiteValue(colorPercentage);
break;
case "3":
effects.SetWhiteValue(colorPercentage, true);
break;
default:
Console.WriteLine("Unknown Selection. Any key to continue.");
Console.ReadKey();
break;
}
}
void RequestPercentage()
{
Console.Write("Please enter the percentage between 0 and 100 in in whole numbers:");
var percentage = Console.ReadLine();
if (int.TryParse(percentage, out int parsedValue))
{
if (parsedValue < 0 || parsedValue > 100)
{
Console.WriteLine("Invalid entry. Value not acceptable.");
}
else
{
colorPercentage = parsedValue / 100.0f;
}
}
Console.WriteLine("Any key to return");
Console.ReadKey();
}
void StartRainbow()
{
Console.WriteLine("Any key to stop");
var cancellationTokenSource = new CancellationTokenSource();
var rainbowTask = Task.Run(() => effects.Rainbow(cancellationTokenSource.Token));
Console.ReadKey();
cancellationTokenSource.Cancel();
rainbowTask.Wait();
effects.SwitchOffLeds();
}
void StartKnightRider()
{
Console.WriteLine("Any key to stop");
var cancellationTokenSource = new CancellationTokenSource();
var knightRiderTask = Task.Run(() => effects.KnightRider(cancellationTokenSource.Token));
Console.ReadKey();
cancellationTokenSource.Cancel();
knightRiderTask.Wait();
effects.SwitchOffLeds();
}
void StartChase(Color color, Color blankColor)
{
Console.WriteLine("Any key to stop");
var cancellationTokenSource = new CancellationTokenSource();
var rainbowTask = Task.Run(() => effects.TheatreChase(color, blankColor, cancellationTokenSource.Token));
Console.ReadKey();
cancellationTokenSource.Cancel();
rainbowTask.Wait();
effects.SwitchOffLeds();
}
// 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.Spi;
using System.Drawing;
using System.Threading;
using Iot.Device.Graphics;
using Iot.Device.Ws28xx;
// Configure the count of pixels
const int Count = 8;
Console.Clear();
SpiConnectionSettings settings = new(0, 0)
{
ClockFrequency = Sk6812.DefaultSpiClockFrequency,
Mode = SpiMode.Mode0,
DataBitLength = 8
};
using SpiDevice spi = SpiDevice.Create(settings);
Sk6812 neo = new Sk6812(spi, Count);
Console.CancelKeyPress += (o, e) =>
{
BitmapImage img = neo.Image;
img.Clear();
neo.Update();
Console.Clear();
};
while (true)
{
Color4Wipe(neo, Color.White, Count);
Color4Wipe(neo, Color.Red, Count);
Color4Wipe(neo, Color.Green, Count);
Color4Wipe(neo, Color.Blue, Count);
Theatre4Chase(neo, Color.White, Count);
Theatre4Chase(neo, Color.Red, Count);
Theatre4Chase(neo, Color.Green, Count);
Theatre4Chase(neo, Color.Blue, Count);
Rainbow4(neo, Count);
Rainbow4Cycle(neo, Count);
TheaterChase4Rainbow(neo, Count);
}
void Color4Wipe(Sk6812 neo, Color color, int count)
{
BitmapImage img = neo.Image;
for (var i = 0; i < count; i++)
{
img.SetPixel(i, 0, color);
neo.Update();
Thread.Sleep(100);
}
}
void Theatre4Chase(Ws28xx neo, Color color, int count, int iterations = 10)
{
BitmapImage img = neo.Image;
for (var i = 0; i < iterations; i++)
{
for (var j = 0; j < 3; j++)
{
for (var k = 0; k < count; k += 3)
{
img.SetPixel(j + k, 0, color);
}
neo.Update();
Thread.Sleep(100);
for (var k = 0; k < count; k += 3)
{
img.SetPixel(j + k, 0, Color.FromArgb(0, 0, 0, 0));
}
}
}
}
Color Wheel4(int position)
{
if (position < 85)
{
return Color.FromArgb(0, position * 3, 255 - position * 3, 0);
}
else if (position < 170)
{
position -= 85;
return Color.FromArgb(0, 255 - position * 3, 0, position * 3);
}
else
{
position -= 170;
return Color.FromArgb(0, 0, position * 3, 255 - position * 3);
}
}
void Rainbow4(Sk6812 neo, int count, int iterations = 1)
{
BitmapImage img = neo.Image;
for (var i = 0; i < 255 * iterations; i++)
{
for (var j = 0; j < count; j++)
{
img.SetPixel(j, 0, Wheel4((i + j) & 255));
}
neo.Update();
Thread.Sleep(50);
}
}
void Rainbow4Cycle(Ws28xx neo, int count, int iterations = 1)
{
BitmapImage img = neo.Image;
for (var i = 0; i < 255 * iterations; i++)
{
for (var j = 0; j < count; j++)
{
img.SetPixel(j, 0, Wheel4(((int)(j * 255 / count) + i) & 255));
}
neo.Update();
Thread.Sleep(50);
}
}
void TheaterChase4Rainbow(Ws28xx neo, int count)
{
BitmapImage img = neo.Image;
for (var i = 0; i < 255; i++)
{
for (var j = 0; j < 3; j++)
{
for (var k = 0; k < count; k += 3)
{
img.SetPixel(k + j, 0, Wheel4((k + i) % 255));
}
neo.Update();
System.Threading.Thread.Sleep(100);
for (var k = 0; k < count; k += 3)
{
img.SetPixel(k + j, 0, Color.FromArgb(0, 0, 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.Spi;
using System.Drawing;
using Iot.Device.Graphics;
using Iot.Device.Ws28xx;
// Configure the count of pixels
const int Count = 8;
Console.Clear();
SpiConnectionSettings settings = new(0, 0)
{
ClockFrequency = 2_400_000,
Mode = SpiMode.Mode0,
DataBitLength = 8
};
using SpiDevice spi = SpiDevice.Create(settings);
#if WS2808
Ws28xx neo = new Ws2808(spi, count);
#else
Ws28xx neo = new Ws2812b(spi, Count);
#endif
Console.CancelKeyPress += (o, e) =>
{
BitmapImage img = neo.Image;
img.Clear();
neo.Update();
Console.Clear();
};
while (true)
{
ColorWipe(neo, Color.White, Count);
ColorWipe(neo, Color.Red, Count);
ColorWipe(neo, Color.Green, Count);
ColorWipe(neo, Color.Blue, Count);
TheatreChase(neo, Color.White, Count);
TheatreChase(neo, Color.Red, Count);
TheatreChase(neo, Color.Green, Count);
TheatreChase(neo, Color.Blue, Count);
Rainbow(neo, Count);
RainbowCycle(neo, Count);
TheaterChaseRainbow(neo, Count);
}
void ColorWipe(Ws28xx neo, Color color, int count)
{
BitmapImage img = neo.Image;
for (var i = 0; i < count; i++)
{
img.SetPixel(i, 0, color);
neo.Update();
}
}
void TheatreChase(Ws28xx neo, Color color, int count, int iterations = 10)
{
BitmapImage img = neo.Image;
for (var i = 0; i < iterations; i++)
{
for (var j = 0; j < 3; j++)
{
for (var k = 0; k < count; k += 3)
{
img.SetPixel(j + k, 0, color);
}
neo.Update();
System.Threading.Thread.Sleep(100);
for (var k = 0; k < count; k += 3)
{
img.SetPixel(j + k, 0, Color.Black);
}
}
}
}
Color Wheel(int position)
{
if (position < 85)
{
return Color.FromArgb(position * 3, 255 - position * 3, 0);
}
else if (position < 170)
{
position -= 85;
return Color.FromArgb(255 - position * 3, 0, position * 3);
}
else
{
position -= 170;
return Color.FromArgb(0, position * 3, 255 - position * 3);
}
}
void Rainbow(Ws28xx neo, int count, int iterations = 1)
{
BitmapImage img = neo.Image;
for (var i = 0; i < 255 * iterations; i++)
{
for (var j = 0; j < count; j++)
{
img.SetPixel(j, 0, Wheel((i + j) & 255));
}
neo.Update();
}
}
void RainbowCycle(Ws28xx neo, int count, int iterations = 1)
{
BitmapImage img = neo.Image;
for (var i = 0; i < 255 * iterations; i++)
{
for (var j = 0; j < count; j++)
{
img.SetPixel(j, 0, Wheel(((int)(j * 255 / count) + i) & 255));
}
neo.Update();
}
}
void TheaterChaseRainbow(Ws28xx neo, int count)
{
BitmapImage img = neo.Image;
for (var i = 0; i < 255; i++)
{
for (var j = 0; j < 3; j++)
{
for (var k = 0; k < count; k += 3)
{
img.SetPixel(k + j, 0, Wheel((k + i) % 255));
}
neo.Update();
System.Threading.Thread.Sleep(100);
for (var k = 0; k < count; k += 3)
{
img.SetPixel(k + j, 0, Color.Black);
}
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(DefaultSampleTfms)</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../Ws28xx.csproj" />
</ItemGroup>
</Project>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册