-
Notifications
You must be signed in to change notification settings - Fork 594
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the Pimoroni Blinkt device binding (#2370)
* Add changes to feat/blinkt * Adding readme * PR feedback * Making sleep time a settable property * Update src/devices/Blinkt/README.md Co-authored-by: Laurent Ellerbach <[email protected]> * Readme changes
- Loading branch information
1 parent
41e17fb
commit dad18cd
Showing
7 changed files
with
391 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
// 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.Gpio; | ||
using System.Threading; | ||
using System.Drawing; | ||
|
||
namespace Iot.Device.Blinkt | ||
{ | ||
/// <summary> | ||
/// Driver for the Pimoroni Blinkt LED strip for Raspbery Pi | ||
/// https://shop.pimoroni.com/products/blinkt | ||
/// | ||
/// This is a strip of 8 pixels that can be indendently controlled over GPIO. | ||
/// | ||
/// Setting the color is a 2-step process: | ||
/// Set the color using Clear, SetPixel, or SetAll | ||
/// Call Show to update the physical pixels | ||
/// </summary> | ||
public class Blinkt : IDisposable | ||
{ | ||
private readonly GpioPin _datPin; | ||
private readonly GpioPin _clkPin; | ||
|
||
private readonly Color[] _pixels = new Color[NumberOfPixels]; | ||
private readonly bool _shouldDispose; | ||
private GpioController _gpioController; | ||
|
||
/// <summary> | ||
/// The number of pixels in the Blinkt strip | ||
/// </summary> | ||
public const int NumberOfPixels = 8; | ||
|
||
/// <summary> | ||
/// The sleep time in milliseconds between each bit written to the Blinkt. | ||
/// | ||
/// The default value of 0 should be enough for most cases and works on the RPi 4 and 5, | ||
/// but you can increase this if you experience issues with the Blinkt on faster CPUs. | ||
/// </summary> | ||
public int SleepTime { get; set; } = 0; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="Blinkt"/> class. | ||
/// </summary> | ||
/// <param name="datPin">The GPIO pin number for the data pin. This defaults to 23, | ||
/// and you should only change this if you connect the blinkt using cables instead of sitting it on the GPIO pins using the provided socket.</param> | ||
/// <param name="clkPin">The GPIO pin number for the clock pin. This defaults to 24, | ||
/// and you should only change this if you connect the blinkt using cables instead of sitting it on the GPIO pins using the provided socket.</param> | ||
/// <param name="gpioController">The GPIO controller to use with the Blinkt. If not provided, a new controller is created.</param> | ||
/// <param name="shouldDispose">True (the default) if the GPIO controller shall be disposed when disposing this instance.</param> | ||
public Blinkt(int datPin = 23, int clkPin = 24, GpioController? gpioController = null, bool shouldDispose = true) | ||
{ | ||
for (int i = 0; i < NumberOfPixels; i++) | ||
{ | ||
_pixels[i] = Color.Empty; | ||
} | ||
|
||
_shouldDispose = shouldDispose || gpioController is null; | ||
_gpioController = gpioController ?? new(); | ||
|
||
_datPin = _gpioController.OpenPin(datPin, PinMode.Output); | ||
_clkPin = _gpioController.OpenPin(clkPin, PinMode.Output); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public void Dispose() | ||
{ | ||
Clear(); | ||
Show(); | ||
|
||
// this condition only applies to GPIO devices | ||
if (_shouldDispose) | ||
{ | ||
_gpioController?.Dispose(); | ||
_gpioController = null!; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Sets the brightness of all the pixels | ||
/// </summary> | ||
/// <param name="brightness">The brightess for the pixels</param> | ||
public void SetBrightness(byte brightness) | ||
{ | ||
for (var i = 0; i < NumberOfPixels; i++) | ||
{ | ||
_pixels[i] = Color.FromArgb(brightness, _pixels[i]); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Clears all the LEDs by turning them off. | ||
/// | ||
/// After calling Clear, you must call Show to update the LEDs. | ||
/// </summary> | ||
public void Clear() | ||
{ | ||
SetAll(Color.Empty); | ||
} | ||
|
||
/// <summary> | ||
/// Shows the current state of the LEDs by applying the colors and brightness to the LEDs. | ||
/// </summary> | ||
public void Show() | ||
{ | ||
Sof(); | ||
|
||
foreach (Color pixel in _pixels) | ||
{ | ||
int r = pixel.R; | ||
int g = pixel.G; | ||
int b = pixel.B; | ||
int brightness = (int)(31.0 * (pixel.A / 255.0)) & 0b11111; | ||
WriteByte(0b11100000 | brightness); | ||
WriteByte(b); | ||
WriteByte(g); | ||
WriteByte(r); | ||
} | ||
|
||
Eof(); | ||
} | ||
|
||
/// <summary> | ||
/// Sets the color of all the pixels. | ||
/// This does not update the physical pixel, you must call Show to display the color. | ||
/// </summary> | ||
/// <param name="color">The color to set the pixel to</param> | ||
public void SetAll(Color color) | ||
{ | ||
for (var i = 0; i < NumberOfPixels; i++) | ||
{ | ||
SetPixel(i, color); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Gets the color that the specified pixel is set to. | ||
/// This may not reflect the actual color of the LED if Show has not been called. | ||
/// </summary> | ||
/// <param name="pixel">The index of the pixel to get</param> | ||
/// <returns>The color of the pixel </returns> | ||
public Color GetPixel(int pixel) | ||
{ | ||
if (pixel < 0 || pixel >= NumberOfPixels) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(pixel), $"Pixel must be between 0 and {NumberOfPixels - 1}"); | ||
} | ||
|
||
return _pixels[pixel]; | ||
} | ||
|
||
/// <summary> | ||
/// Sets the color of the specified pixel to the specified color. | ||
/// This does not update the physical pixel, you must call Show to display the color. | ||
/// </summary> | ||
/// <param name="pixel">The index of the pixel to update</param> | ||
/// <param name="color">The color to set on the pixel</param> | ||
/// <exception cref="ArgumentOutOfRangeException">The value of pixel must be between 0 and 7, otherwise this exception is thrown</exception> | ||
public void SetPixel(int pixel, Color color) | ||
{ | ||
if (pixel < 0 || pixel >= NumberOfPixels) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(pixel), $"Pixel must be between 0 and {NumberOfPixels - 1}"); | ||
} | ||
|
||
_pixels[pixel] = color; | ||
} | ||
|
||
private void WriteByte(int b) | ||
{ | ||
for (var i = 0; i < 8; i++) | ||
{ | ||
_datPin.Write((b & 0b10000000) != 0); | ||
_clkPin.Write(PinValue.High); | ||
Thread.Sleep(SleepTime); | ||
b <<= 1; | ||
_clkPin.Write(PinValue.Low); | ||
Thread.Sleep(SleepTime); | ||
} | ||
} | ||
|
||
private void Eof() | ||
{ | ||
_datPin.Write(PinValue.Low); | ||
for (var i = 0; i < 36; i++) | ||
{ | ||
_clkPin.Write(PinValue.High); | ||
Thread.Sleep(SleepTime); | ||
_clkPin.Write(PinValue.Low); | ||
Thread.Sleep(SleepTime); | ||
} | ||
} | ||
|
||
private void Sof() | ||
{ | ||
_datPin.Write(PinValue.Low); | ||
for (var i = 0; i < 32; i++) | ||
{ | ||
_clkPin.Write(PinValue.High); | ||
Thread.Sleep(SleepTime); | ||
_clkPin.Write(PinValue.Low); | ||
Thread.Sleep(SleepTime); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFrameworks>$(DefaultBindingTfms)</TargetFrameworks> | ||
<!--Disabling default items so samples source won't get build by the main library--> | ||
<EnableDefaultItems>false</EnableDefaultItems> | ||
<LangVersion>9</LangVersion> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Compile Include="*.cs" /> | ||
<None Include="README.md" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio 15 | ||
VisualStudioVersion = 15.0.26124.0 | ||
MinimumVisualStudioVersion = 15.0.26124.0 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blinkt", "Blinkt.csproj", "{B82C190A-642B-465B-BD3F-DB56FFF22253}" | ||
EndProject | ||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{6A4DE7B1-03F3-4EE0-BF73-A0BAEF88BA2B}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blinkt.Samples", "samples\Blinkt.Samples.csproj", "{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "..\Common\Common.csproj", "{584651BB-91DA-4FFE-B32C-F13DD7BCE100}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Debug|x64 = Debug|x64 | ||
Debug|x86 = Debug|x86 | ||
Release|Any CPU = Release|Any CPU | ||
Release|x64 = Release|x64 | ||
Release|x86 = Release|x86 | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Debug|x64.Build.0 = Debug|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Debug|x86.Build.0 = Debug|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Release|x64.ActiveCfg = Release|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Release|x64.Build.0 = Release|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Release|x86.ActiveCfg = Release|Any CPU | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF}.Release|x86.Build.0 = Release|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Debug|x64.Build.0 = Debug|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Debug|x86.Build.0 = Debug|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Release|x64.ActiveCfg = Release|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Release|x64.Build.0 = Release|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Release|x86.ActiveCfg = Release|Any CPU | ||
{B82C190A-642B-465B-BD3F-DB56FFF22253}.Release|x86.Build.0 = Release|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Debug|x64.Build.0 = Debug|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Debug|x86.Build.0 = Debug|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Release|x64.ActiveCfg = Release|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Release|x64.Build.0 = Release|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Release|x86.ActiveCfg = Release|Any CPU | ||
{584651BB-91DA-4FFE-B32C-F13DD7BCE100}.Release|x86.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(NestedProjects) = preSolution | ||
{3CFA13D6-1D29-4C87-B0C1-01A6901A50EF} = {6A4DE7B1-03F3-4EE0-BF73-A0BAEF88BA2B} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Blinkt - 8-LED indicator strip | ||
|
||
## Summary | ||
|
||
[Blinkt!](https://shop.pimoroni.com/products/blinkt) offers eight APA102 pixels in the smallest (and cheapest) form factor to plug straight onto your Raspberry Pi. | ||
|
||
Each pixel on Blinkt! is individually controllable and dimmable allowing you to create gradients, pulsing effects, or just flash them on and off like crazy. | ||
|
||
## Binding Notes | ||
|
||
The Blinkt has 8 pixels that can be controlled independantly. This library is designed to mimic the functionality of the [Pimoroni Blinkt Python library](https://github.com/pimoroni/blinkt), except using System.Drawing.Color instead of separate R, G, B and brightness values. the Alpha channnel is used to set the brightness of the pixel. | ||
|
||
Setting the pixel values does not update the display. You must call the `Show` method to update the display. This allows you to configure how you want all the pixels to look before updating the display. | ||
|
||
## Usage | ||
|
||
Here is an example how to use the Blinkt: | ||
|
||
```csharp | ||
using System.Drawing; | ||
using Iot.Device.Blinkt; | ||
|
||
// Create the Blinkt | ||
var blinkt = new Blinkt(); | ||
|
||
// Set all the pixels to random colors | ||
for (int i = 0; i < Blinkt.NUMBER_OF_PIXELS; i++) | ||
{ | ||
var color = Color.FromArgb(new Random().Next(0, 255), new Random().Next(0, 255), new Random().Next(0, 255)); | ||
blinkt.SetPixel(i, color); | ||
} | ||
|
||
// Update the display to show the new colors | ||
blinkt.Show(); | ||
``` | ||
|
||
## References | ||
|
||
[Blinkt on Pimoroni](https://shop.pimoroni.com/products/blinkt) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
display | ||
led |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// 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.Drawing; | ||
using System.Threading; | ||
using Iot.Device.Blinkt; | ||
|
||
// Light up pixels moving backwards and forwards in random colors | ||
|
||
// Create a new Blinkt instance | ||
Blinkt blinkt = new Blinkt(); | ||
|
||
// A helper method to set a single pixel to a given color, clearing all others. | ||
// This also waits 100ms so the color can be seen | ||
static void SetOnePixel(Blinkt blinkt, Color color, int i) | ||
{ | ||
// Turn all pixels off first - this is not reflected in the hardware till we call Show | ||
blinkt.Clear(); | ||
|
||
// Set the pixel at index i to the given color | ||
blinkt.SetPixel(i, color); | ||
|
||
// Update the hardware to reflect the changes | ||
blinkt.Show(); | ||
|
||
// Wait for a bit before moving to the next pixel | ||
Thread.Sleep(100); | ||
} | ||
|
||
// Loop forever | ||
while (true) | ||
{ | ||
// Generate a random color | ||
Color color = Color.FromArgb(new Random().Next(0, 255), new Random().Next(0, 255), new Random().Next(0, 255)); | ||
|
||
// Loop through the pixels, lighting them in the given color | ||
for (int i = 0; i < Blinkt.NumberOfPixels; i++) | ||
{ | ||
SetOnePixel(blinkt, color, i); | ||
} | ||
|
||
// Loop through the pixels in reverse order, lighting them in the given color | ||
// We skip the first pixel so there is a more pleasing bounce effect | ||
for (int i = Blinkt.NumberOfPixels - 2; i >= 0; i--) | ||
{ | ||
SetOnePixel(blinkt, color, i); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>$(DefaultSampleTfms)</TargetFramework> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="../Blinkt.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |