From 8299345ba0329b58e3b246261191ea37d3aca102 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 21 Sep 2022 16:15:50 -0700 Subject: [PATCH 01/46] Binding for IS31FL3731 LED Matrix driver --- src/devices/Is31fl3730/Is31fl3730.cs | 188 +++++++++++++++++++++++ src/devices/Is31fl3730/Is31fl3730.csproj | 10 ++ src/devices/Is31fl3730/MatrixMode.cs | 23 +++ src/devices/Is31fl3730/README.md | 13 ++ 4 files changed, 234 insertions(+) create mode 100644 src/devices/Is31fl3730/Is31fl3730.cs create mode 100644 src/devices/Is31fl3730/Is31fl3730.csproj create mode 100644 src/devices/Is31fl3730/MatrixMode.cs create mode 100644 src/devices/Is31fl3730/README.md diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs new file mode 100644 index 0000000000..e54b9b5f4e --- /dev/null +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -0,0 +1,188 @@ +// 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.Threading; +using System.Threading.Tasks; +using System.Device.Gpio; +using System.Device.Spi; +using Iot.Device.Multiplexing.Utility; + +namespace Iot.Device.Display +{ + /// + /// Represents an IS31FL3731 LED Matrix driver + /// + // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf + // Product: https://shop.pimoroni.com/products/microdot-phat + // Related repo: https://github.com/pimoroni/microdot-phat + public class Is31fl3730 : IDisposable + { + // Function register + // table 2 in datasheet + private const byte CONFIGURATION_REGISTER = 0x0; + private const byte MATRIX_1_REGISTER = 0x1; + private const byte MATRIX_1_REGISTER_LENGTH = MATRIX_2_REGISTER - MATRIX_1_REGISTER; + private const byte MATRIX_2_REGISTER = 0xE; + private const byte MATRIX_2_REGISTER_LENGTH = UPDATE_COLUMN_REGISTER - MATRIX_2_REGISTER; + private const byte UPDATE_COLUMN_REGISTER = 0xC; + private const byte LIGHTING_EFFECT_REGISTER = 0xD; + private const byte PWM_REGISTER = 0x19; + private const byte RESET_REGISTER = 0xC; + + + // Configuration register + // table 3 in datasheet + private const byte SHUTDOWN = 0x80; + private const byte DISPLAY_MATRIX_ONE = 0x0; + private const byte DISPLAY_MATRIX_TWO = 0x8; + private const byte DISPLAY_MATRIX_BOTH = 0x18; + private const byte MATRIX_8x8 = 0x0; + private const byte MATRIX_7x9 = 0x1; + private const byte MATRIX_6x10 = 0x2; + private const byte MATRIX_5x11 = 0x3; + + /// + /// Initialize IS31FL3730 device + /// + /// The to create with. + public Is31fl3730(I2cDevice i2cDevice) + { + _i2cDevice = i2cDevice; + // _enable_all_leds_data.AsSpan().Fill(0xff); + + } + + /// + /// Initialize IS31FL3730 device + /// + /// The to create with. + /// The width of the LED matrix. + /// The height of the LED matrix. + public Is31Fl3731(I2cDevice i2cDevice, int width, int height) + : this(i2cDevice) + { + Width = width; + Height = height; + } + + /// + /// Default I2C address for device. + /// + public static readonly int DefaultI2cAddress; + + /// + /// Width of LED matrix (x axis). + /// + public readonly int Width = 16; + + /// + /// Height of LED matrix (y axis). + /// + public readonly int Height = 9; + + private int _configurationValue = 0; + + /// + /// Initialize LED driver. + /// + public void Initialize() + { + // Reset device + Reset(); + + // set display mode (bits d4:d3) + // 00 = picture mode + // 01 = auto frame + // 1x audio frame play mode + Write(FUNCTION_REGISTER, CONFIGURATION_REGISTER, 0); + SetDisplayMode(true, false); + SetMatrixMode(MatrixMode.Size8x8); + } + + /// + /// Indexer for updating matrix, with PWM register. + /// + public int this[int x, int y] + { + get => ReadLedPwm(x, y); + set => WriteLedPwm(x, y, value); + } + + /// + /// Reset device. + /// + public void Reset() + { + // Reset device + Shutdown(true); + Thread.Sleep(10); + Shutdown(false); + } + + /// + /// Set the shutdown mode. + /// + /// Set the showdown mode. `true` sets device into shutdown mode. `false` sets device into normal operation. + public void Shutdown(bool shutdown) + { + // mode values + // 0 = normal operation + // 1 = shutdown mode + if (shutdown) + { + _configurationValue |= SHUTDOWN; + } + else + { + _configurationValue &= ~SHUTDOWN; + } + + Write(CONFIGURATION_REGISTER, _configurationValue); + } + + private void SetDisplayMode(bool matrixOne, bool matrixTwo) + { + if (matrixOne && matrixTwo) + { + _configurationValue |= DISPLAY_MATRIX_BOTH; + } + else if (matrixOne) + { + _configurationValue |= DISPLAY_MATRIX_ONE; + } + else if (matrixTwo) + { + _configurationValue |= DISPLAY_MATRIX_TWO; + } + } + + private void SetMatrixMode(MatrixMode mode) + { + if (mode is MatrixMode.Size5x11) + { + _configurationValue |= MATRIX_5x11; + } + else if (mode is MatrixMode.Size6x10) + { + _configurationValue |= MATRIX_6x10; + } + else if (mode is MatrixMode.Size7x9) + { + _configurationValue |= MATRIX_7x9; + } + else if (mode is MatrixMode.Size8x8) + { + _configurationValue |= MATRIX_8x8; + } + } + + private void Write(byte address, byte[] value) + { + byte[] data = new byte[value.Length + 1]; + data[0] = address; + value.CopyTo(data.AsSpan(1)); + _i2cDevice.Write(data); + } + } +} diff --git a/src/devices/Is31fl3730/Is31fl3730.csproj b/src/devices/Is31fl3730/Is31fl3730.csproj new file mode 100644 index 0000000000..dee6da6145 --- /dev/null +++ b/src/devices/Is31fl3730/Is31fl3730.csproj @@ -0,0 +1,10 @@ + + + $(DefaultBindingTfms) + false + + + + + + \ No newline at end of file diff --git a/src/devices/Is31fl3730/MatrixMode.cs b/src/devices/Is31fl3730/MatrixMode.cs new file mode 100644 index 0000000000..e3c605f2e1 --- /dev/null +++ b/src/devices/Is31fl3730/MatrixMode.cs @@ -0,0 +1,23 @@ +// 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.Threading; +using System.Threading.Tasks; +using System.Device.Gpio; +using System.Device.Spi; +using Iot.Device.Multiplexing.Utility; + +namespace Iot.Device.Display +{ + /// + /// Represents an IS31FL3731 LED Matrix driver + /// + public enum MatrixMode + { + Size8x8, + Size7x9, + Size6x10, + Size5x11 + } +} diff --git a/src/devices/Is31fl3730/README.md b/src/devices/Is31fl3730/README.md new file mode 100644 index 0000000000..f21a090159 --- /dev/null +++ b/src/devices/Is31fl3730/README.md @@ -0,0 +1,13 @@ + # IS31FL3730 -- LED Matrix Display Driver + +The [IS31FL3730](https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf) is a compact LED driver that can drive one or two 8×8, 7×9, 6×10, or 5×11 dot matrix displays. The device can be programmed via an I2C compatible interface. + +This binding is similar to the Python version in [pimoroni/microdot-phat](https://github.com/pimoroni/microdot-phat). + +## Micro Dot pHAT + +An unashamedly old school LED matrix display board, made up of six LED matrices each 5x7 pixels (for an effective display area of 30x7) plus a decimal point, using the beautiful little Lite-On LTP-305 matrices. + + + +You can write the following code to control them or checkout a larger sample. From ccd9b9a1e39fc3966c3374e5c6487b0d4e882908 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 21 Sep 2022 22:31:39 -0700 Subject: [PATCH 02/46] Add sample --- src/devices/Is31fl3730/Is31fl3730.cs | 154 ++++++++++++------ src/devices/Is31fl3730/MatrixMode.cs | 15 ++ .../Is31fl3730/samples/MicroDotPhat.csproj | 11 ++ src/devices/Is31fl3730/samples/Program.cs | 13 ++ 4 files changed, 144 insertions(+), 49 deletions(-) create mode 100644 src/devices/Is31fl3730/samples/MicroDotPhat.csproj create mode 100644 src/devices/Is31fl3730/samples/Program.cs diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index e54b9b5f4e..aec43b5e4a 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; +using System.Device.I2c; using System.Threading; -using System.Threading.Tasks; -using System.Device.Gpio; -using System.Device.Spi; -using Iot.Device.Multiplexing.Utility; namespace Iot.Device.Display { @@ -22,14 +20,13 @@ public class Is31fl3730 : IDisposable // table 2 in datasheet private const byte CONFIGURATION_REGISTER = 0x0; private const byte MATRIX_1_REGISTER = 0x1; - private const byte MATRIX_1_REGISTER_LENGTH = MATRIX_2_REGISTER - MATRIX_1_REGISTER; + private const int MATRIX_1_REGISTER_LENGTH = MATRIX_2_REGISTER - MATRIX_1_REGISTER; private const byte MATRIX_2_REGISTER = 0xE; - private const byte MATRIX_2_REGISTER_LENGTH = UPDATE_COLUMN_REGISTER - MATRIX_2_REGISTER; + private const int MATRIX_2_REGISTER_LENGTH = UPDATE_COLUMN_REGISTER - MATRIX_2_REGISTER; private const byte UPDATE_COLUMN_REGISTER = 0xC; private const byte LIGHTING_EFFECT_REGISTER = 0xD; private const byte PWM_REGISTER = 0x19; private const byte RESET_REGISTER = 0xC; - // Configuration register // table 3 in datasheet @@ -42,6 +39,15 @@ public class Is31fl3730 : IDisposable private const byte MATRIX_6x10 = 0x2; private const byte MATRIX_5x11 = 0x3; + // Values + private readonly byte[] _disable_all_leds_data = new byte[8]; + private readonly byte[] _enable_all_leds_data = new byte[MATRIX_1_REGISTER_LENGTH]; + private byte[] _matrix1 = new byte[MATRIX_1_REGISTER_LENGTH]; + private byte[] _matrix2 = new byte[MATRIX_1_REGISTER_LENGTH]; + private List _matrices = new(); + + private I2cDevice _i2cDevice; + /// /// Initialize IS31FL3730 device /// @@ -49,8 +55,9 @@ public class Is31fl3730 : IDisposable public Is31fl3730(I2cDevice i2cDevice) { _i2cDevice = i2cDevice; - // _enable_all_leds_data.AsSpan().Fill(0xff); - + _enable_all_leds_data.AsSpan().Fill(0xff); + _matrices.Add(_matrix1); + _matrices.Add(_matrix2); } /// @@ -59,7 +66,7 @@ public Is31fl3730(I2cDevice i2cDevice) /// The to create with. /// The width of the LED matrix. /// The height of the LED matrix. - public Is31Fl3731(I2cDevice i2cDevice, int width, int height) + public Is31fl3730(I2cDevice i2cDevice, int width, int height) : this(i2cDevice) { Width = width; @@ -69,7 +76,7 @@ public Is31Fl3731(I2cDevice i2cDevice, int width, int height) /// /// Default I2C address for device. /// - public static readonly int DefaultI2cAddress; + public static readonly int DefaultI2cAddress = 0x63; /// /// Width of LED matrix (x axis). @@ -80,7 +87,7 @@ public Is31Fl3731(I2cDevice i2cDevice, int width, int height) /// Height of LED matrix (y axis). /// public readonly int Height = 9; - + private int _configurationValue = 0; /// @@ -90,23 +97,39 @@ public void Initialize() { // Reset device Reset(); - - // set display mode (bits d4:d3) - // 00 = picture mode - // 01 = auto frame - // 1x audio frame play mode - Write(FUNCTION_REGISTER, CONFIGURATION_REGISTER, 0); - SetDisplayMode(true, false); + SetDisplayMode(true, true); SetMatrixMode(MatrixMode.Size8x8); + WriteConfiguration(); + DisableAllLeds(); } /// /// Indexer for updating matrix, with PWM register. /// - public int this[int x, int y] + public int this[int x, int y, int matrix] + { + // get => ReadLedPwm(x, y); + set => WriteLed(matrix, x, y, value); + } + + /// + /// Enable all LEDs. + /// + public void EnableAllLeds() + { + Write(MATRIX_1_REGISTER, _enable_all_leds_data); + Write(MATRIX_2_REGISTER, _enable_all_leds_data); + WriteUpdateRegister(); + } + + /// + /// Disable all LEDs. + /// + public void DisableAllLeds() { - get => ReadLedPwm(x, y); - set => WriteLedPwm(x, y, value); + Write(MATRIX_1_REGISTER, _disable_all_leds_data); + Write(MATRIX_2_REGISTER, _disable_all_leds_data); + WriteUpdateRegister(); } /// @@ -138,43 +161,42 @@ public void Shutdown(bool shutdown) _configurationValue &= ~SHUTDOWN; } - Write(CONFIGURATION_REGISTER, _configurationValue); + WriteUpdateRegister(); + } + + /// + public void Dispose() + { + _i2cDevice?.Dispose(); + _i2cDevice = null!; } private void SetDisplayMode(bool matrixOne, bool matrixTwo) { - if (matrixOne && matrixTwo) - { - _configurationValue |= DISPLAY_MATRIX_BOTH; - } - else if (matrixOne) + _configurationValue |= (matrixOne, matrixTwo) switch { - _configurationValue |= DISPLAY_MATRIX_ONE; - } - else if (matrixTwo) - { - _configurationValue |= DISPLAY_MATRIX_TWO; - } + (true, true) => DISPLAY_MATRIX_BOTH, + (true, _) => DISPLAY_MATRIX_ONE, + (_, true) => DISPLAY_MATRIX_TWO, + _ => throw new Exception("Invalid input.") + }; } private void SetMatrixMode(MatrixMode mode) { - if (mode is MatrixMode.Size5x11) - { - _configurationValue |= MATRIX_5x11; - } - else if (mode is MatrixMode.Size6x10) - { - _configurationValue |= MATRIX_6x10; - } - else if (mode is MatrixMode.Size7x9) - { - _configurationValue |= MATRIX_7x9; - } - else if (mode is MatrixMode.Size8x8) + _configurationValue |= mode switch { - _configurationValue |= MATRIX_8x8; - } + MatrixMode.Size5x11 => MATRIX_5x11, + MatrixMode.Size6x10 => MATRIX_6x10, + MatrixMode.Size7x9 => MATRIX_7x9, + MatrixMode.Size8x8 => MATRIX_8x8, + _ => throw new Exception("Invalid input.") + }; + } + + private void WriteConfiguration() + { + Write(CONFIGURATION_REGISTER, (byte)_configurationValue); } private void Write(byte address, byte[] value) @@ -184,5 +206,39 @@ private void Write(byte address, byte[] value) value.CopyTo(data.AsSpan(1)); _i2cDevice.Write(data); } + + private void Write(byte address, byte value) + { + _i2cDevice.Write(new byte[] { address, value }); + } + + private void WriteLed(int matrix, int x, int y, int enable) + { + byte[] m = _matrices[matrix]; + byte mask = (byte)(1 >> x); + + if (enable is 1) + { + m[y] |= mask; + } + else + { + m[y] &= (byte)(~mask); + } + + UpdateMatrixRegisters(); + } + + private void WriteUpdateRegister() + { + Write(UPDATE_COLUMN_REGISTER, 0x80); + } + + private void UpdateMatrixRegisters() + { + Write(MATRIX_1_REGISTER, _matrix1); + Write(MATRIX_2_REGISTER, _matrix2); + WriteUpdateRegister(); + } } } diff --git a/src/devices/Is31fl3730/MatrixMode.cs b/src/devices/Is31fl3730/MatrixMode.cs index e3c605f2e1..9385571bd7 100644 --- a/src/devices/Is31fl3730/MatrixMode.cs +++ b/src/devices/Is31fl3730/MatrixMode.cs @@ -15,9 +15,24 @@ namespace Iot.Device.Display /// public enum MatrixMode { + /// + /// Represents a 8x8 LED matrix. + /// Size8x8, + + /// + /// Represents a 7x9 LED matrix. + /// Size7x9, + + /// + /// Represents a 6x10 LED matrix. + /// Size6x10, + + /// + /// Represents an 5x11 LED matrix. + /// Size5x11 } } diff --git a/src/devices/Is31fl3730/samples/MicroDotPhat.csproj b/src/devices/Is31fl3730/samples/MicroDotPhat.csproj new file mode 100644 index 0000000000..19d5e14bfb --- /dev/null +++ b/src/devices/Is31fl3730/samples/MicroDotPhat.csproj @@ -0,0 +1,11 @@ + + + Exe + $(DefaultBindingTfms) + false + + + + + + \ No newline at end of file diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs new file mode 100644 index 0000000000..1eb6d834da --- /dev/null +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -0,0 +1,13 @@ +// 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.I2c; +using System.Threading; +using Iot.Device.Display; + +using Is31fl3730 matrix = new(I2cDevice.Create(new I2cConnectionSettings(busId: 1, Is31fl3730.DefaultI2cAddress))); + +matrix.Initialize(); +matrix[0, 5, 0] = 1; +matrix[1, 5, 1] = 1; From be62d432063a25ce5b357a0cff4baf9b751d8a45 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Thu, 22 Sep 2022 21:27:04 -0700 Subject: [PATCH 03/46] Update sample --- src/devices/Is31fl3730/Is31fl3730.cs | 153 ++++++++++++++-------- src/devices/Is31fl3730/samples/Program.cs | 12 +- 2 files changed, 112 insertions(+), 53 deletions(-) diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index aec43b5e4a..8a3d9df288 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -20,13 +20,11 @@ public class Is31fl3730 : IDisposable // table 2 in datasheet private const byte CONFIGURATION_REGISTER = 0x0; private const byte MATRIX_1_REGISTER = 0x1; - private const int MATRIX_1_REGISTER_LENGTH = MATRIX_2_REGISTER - MATRIX_1_REGISTER; - private const byte MATRIX_2_REGISTER = 0xE; - private const int MATRIX_2_REGISTER_LENGTH = UPDATE_COLUMN_REGISTER - MATRIX_2_REGISTER; - private const byte UPDATE_COLUMN_REGISTER = 0xC; - private const byte LIGHTING_EFFECT_REGISTER = 0xD; + private const byte MATRIX_2_REGISTER = 0x0E; + private const byte UPDATE_COLUMN_REGISTER = 0x0C; + private const byte LIGHTING_EFFECT_REGISTER = 0x0D; private const byte PWM_REGISTER = 0x19; - private const byte RESET_REGISTER = 0xC; + private const byte RESET_REGISTER = 0x0C; // Configuration register // table 3 in datasheet @@ -41,12 +39,11 @@ public class Is31fl3730 : IDisposable // Values private readonly byte[] _disable_all_leds_data = new byte[8]; - private readonly byte[] _enable_all_leds_data = new byte[MATRIX_1_REGISTER_LENGTH]; - private byte[] _matrix1 = new byte[MATRIX_1_REGISTER_LENGTH]; - private byte[] _matrix2 = new byte[MATRIX_1_REGISTER_LENGTH]; - private List _matrices = new(); - + private readonly byte[] _enable_all_leds_data = new byte[8]; + private byte[] _matrix1 = new byte[8]; + private byte[] _matrix2 = new byte[8]; private I2cDevice _i2cDevice; + private int _configurationValue = 0; /// /// Initialize IS31FL3730 device @@ -55,9 +52,15 @@ public class Is31fl3730 : IDisposable public Is31fl3730(I2cDevice i2cDevice) { _i2cDevice = i2cDevice; - _enable_all_leds_data.AsSpan().Fill(0xff); - _matrices.Add(_matrix1); - _matrices.Add(_matrix2); + // _enable_all_leds_data.AsSpan().Fill(0xff); + _enable_all_leds_data[0] = 127; + _enable_all_leds_data[1] = 127; + _enable_all_leds_data[2] = 127; + _enable_all_leds_data[3] = 127; + _enable_all_leds_data[4] = 0; + _enable_all_leds_data[5] = 0; + _enable_all_leds_data[6] = 16; + _enable_all_leds_data[7] = 64; } /// @@ -88,25 +91,41 @@ public Is31fl3730(I2cDevice i2cDevice, int width, int height) /// public readonly int Height = 9; - private int _configurationValue = 0; + /// + /// Brightness of LED matrix (override default value (40 mA); set before calling Initialize method). + /// + public int Brightness = 128; + + /// + /// Full current setting for each row output of LED matrix (override default value (128; max brightness); set before calling Initialize method). + /// + public int CurrentSetting = 0b00001110; /// /// Initialize LED driver. /// public void Initialize() { - // Reset device - Reset(); - SetDisplayMode(true, true); - SetMatrixMode(MatrixMode.Size8x8); - WriteConfiguration(); - DisableAllLeds(); + if (_configurationValue > 0) + { + WriteConfiguration(); + } + + if (CurrentSetting > 0) + { + _i2cDevice.Write(new byte[] { LIGHTING_EFFECT_REGISTER, (byte)CurrentSetting }); + } + + if (Brightness > 0) + { + _i2cDevice.Write(new byte[] { PWM_REGISTER, (byte)Brightness }); + } } /// /// Indexer for updating matrix, with PWM register. /// - public int this[int x, int y, int matrix] + public int this[int matrix, int x, int y] { // get => ReadLedPwm(x, y); set => WriteLed(matrix, x, y, value); @@ -118,7 +137,7 @@ public void Initialize() public void EnableAllLeds() { Write(MATRIX_1_REGISTER, _enable_all_leds_data); - Write(MATRIX_2_REGISTER, _enable_all_leds_data); + // Write(MATRIX_2_REGISTER, _enable_all_leds_data); WriteUpdateRegister(); } @@ -132,6 +151,35 @@ public void DisableAllLeds() WriteUpdateRegister(); } + /// + /// Set display mode. Call before Initialize method. + /// + public void SetDisplayMode(bool matrixOne, bool matrixTwo) + { + _configurationValue |= (matrixOne, matrixTwo) switch + { + (true, true) => DISPLAY_MATRIX_BOTH, + (true, _) => DISPLAY_MATRIX_ONE, + (_, true) => DISPLAY_MATRIX_TWO, + _ => throw new Exception("Invalid input.") + }; + } + + /// + /// Set matrix mode. Call before Initialize method. + /// + public void SetMatrixMode(MatrixMode mode) + { + _configurationValue |= mode switch + { + MatrixMode.Size5x11 => MATRIX_5x11, + MatrixMode.Size6x10 => MATRIX_6x10, + MatrixMode.Size7x9 => MATRIX_7x9, + MatrixMode.Size8x8 => MATRIX_8x8, + _ => throw new Exception("Invalid input.") + }; + } + /// /// Reset device. /// @@ -171,29 +219,6 @@ public void Dispose() _i2cDevice = null!; } - private void SetDisplayMode(bool matrixOne, bool matrixTwo) - { - _configurationValue |= (matrixOne, matrixTwo) switch - { - (true, true) => DISPLAY_MATRIX_BOTH, - (true, _) => DISPLAY_MATRIX_ONE, - (_, true) => DISPLAY_MATRIX_TWO, - _ => throw new Exception("Invalid input.") - }; - } - - private void SetMatrixMode(MatrixMode mode) - { - _configurationValue |= mode switch - { - MatrixMode.Size5x11 => MATRIX_5x11, - MatrixMode.Size6x10 => MATRIX_6x10, - MatrixMode.Size7x9 => MATRIX_7x9, - MatrixMode.Size8x8 => MATRIX_8x8, - _ => throw new Exception("Invalid input.") - }; - } - private void WriteConfiguration() { Write(CONFIGURATION_REGISTER, (byte)_configurationValue); @@ -214,19 +239,45 @@ private void Write(byte address, byte value) private void WriteLed(int matrix, int x, int y, int enable) { - byte[] m = _matrices[matrix]; - byte mask = (byte)(1 >> x); + /* + The following diagrams and information demonstrate how the matrix is structured. + + This in terms of two products: + - https://shop.pimoroni.com/products/microdot-phat + - https://shop.pimoroni.com/products/led-dot-matrix-breakout + + + Both of these products present pairs of 5x7 LED mattrices. + + */ + if (matrix is 0) + { + byte mask = (byte)(1 << x); + _matrix1[y] = UpdateByte(_matrix1[y], mask, enable); + } + else if (matrix is 1) + { + byte mask = (byte)(1 << y); + _matrix2[x] = UpdateByte(_matrix2[x], mask, enable); + + } + + UpdateMatrixRegisters(); + } + + private byte UpdateByte(byte data, byte mask, int enable) + { if (enable is 1) { - m[y] |= mask; + data |= mask; } else { - m[y] &= (byte)(~mask); + data &= (byte)(~mask); } - UpdateMatrixRegisters(); + return data; } private void WriteUpdateRegister() diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 1eb6d834da..deccd574ef 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -8,6 +8,14 @@ using Is31fl3730 matrix = new(I2cDevice.Create(new I2cConnectionSettings(busId: 1, Is31fl3730.DefaultI2cAddress))); +// matrix.Brightness = 127; matrix.Initialize(); -matrix[0, 5, 0] = 1; -matrix[1, 5, 1] = 1; +matrix.DisableAllLeds(); +Thread.Sleep(100); +matrix.EnableAllLeds(); +// Thread.Sleep(100); +// matrix[0, 4, 3] = 1; +// matrix[0, 4, 4] = 1; +// matrix[0, 4, 5] = 1; +// matrix[0, 4, 6] = 1; +// matrix[0, 0, 7] = 1; From 7b78e6fee58f3ae297d36231dc40c5ba1685ae42 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Fri, 23 Sep 2022 12:16:10 -0700 Subject: [PATCH 04/46] Update comments --- src/devices/Is31fl3730/Is31fl3730.cs | 89 ++++++++++++++++++- .../Is31fl3730/samples/MicroDotPhat.csproj | 2 +- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 8a3d9df288..b1b94cf48e 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -13,6 +13,7 @@ namespace Iot.Device.Display /// // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf // Product: https://shop.pimoroni.com/products/microdot-phat + // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat public class Is31fl3730 : IDisposable { @@ -53,7 +54,7 @@ public Is31fl3730(I2cDevice i2cDevice) { _i2cDevice = i2cDevice; // _enable_all_leds_data.AsSpan().Fill(0xff); - _enable_all_leds_data[0] = 127; + _enable_all_leds_data[0] = 37; _enable_all_leds_data[1] = 127; _enable_all_leds_data[2] = 127; _enable_all_leds_data[3] = 127; @@ -79,7 +80,27 @@ public Is31fl3730(I2cDevice i2cDevice, int width, int height) /// /// Default I2C address for device. /// - public static readonly int DefaultI2cAddress = 0x63; + /* + The Pimoroni devices support three I2C devices: + + - 0x61 (the default) + - 0x62 + - 0x63 + + For the breakout, this is straightforward. There is a default and you can change the address (in the normal way). + + For the Micro Dot pHAT, there are three pairs installed (making six matrices). The addresses are ordered this way: + + x63 x62 x61 + ________ _________ ________ + m2 | m1 || m2 | m1 || m2 | m1 + + This ordering makes sense if you are scrolling content right to left. + + More detailed information about the structure of each pair follows (later in doc). + + */ + public static readonly int DefaultI2cAddress = 0x61; /// /// Width of LED matrix (x axis). @@ -250,7 +271,71 @@ private void WriteLed(int matrix, int x, int y, int enable) Both of these products present pairs of 5x7 LED mattrices. + *matrix 2* + xxxxx | xxxxx + xxxxx | xxxxx + xxxxx | xxxxx + xxxxx | xxxxx + xxxxx | xxxxx + xxxxx | xxxxx + xxxxx | xxxxx + x x + *matrix 1* + + Matrix 1 (as demonstrated) is right-most. This makes sense if you scroll content from right to left. + + Each matrices has a (somewhat odd) dot in the bottom left. It has to be enabled in a special way. + + The matrices are updated with quite different data patterns: + + - matrix 1 is row-based. + - matrix 2 is column based. + + Let's write a byte to both matrices and see what happens. + + Byte: 00011001 + + The following is displayed -- "o" means lit; "x" is unlit. + + *matrix 2* + oxxxx | oxxoo + xxxxx | xxxxx + xxxxx | xxxxx + oxxxx | xxxxx + oxxxx | xxxxx + xxxxx | xxxxx + xxxxx | xxxxx + x x + *matrix 1* + + Straightforwardly, both matrices start in the top-left, however + matrix 1 is row-based, left to right and matrix 2 is column-based + up to down. + + You will notice these matrices are not symmetrical when you consider + rows vs columns. Theses matrices are 5x7 not 5x5 or 7x7. + + That means that writing a byte -- 1000_0000 -- with just the high bit set + won't do anything for either matrix since that bit effectively "falls off". + + Does this matter? Sorta. + + If you are updating one pixel at a time, then you just need to update the + correct bit, one at a time, either row- or column-based (as you see in + the code below). + + If you have a bitmap you want to write all at once, then you can simply write + rows of bytes to matrix 1. However, you need to ensure your bitmap only uses + the first 5 bits. If you are writing to matrix 2 then writing one row at a + time won't work. Your content will be 90d flipped and the content (if you write + the same 5-bit encoded bitmap) will be 2 pixels short. Instead, you need to + translate row-based content to columns, similar to the `else` clause below. + + Separately, you can disable one matrix or the other. That's largely a separate + concern. It has nothing to do with byte structure. + */ + if (matrix is 0) { byte mask = (byte)(1 << x); diff --git a/src/devices/Is31fl3730/samples/MicroDotPhat.csproj b/src/devices/Is31fl3730/samples/MicroDotPhat.csproj index 19d5e14bfb..9de2921e45 100644 --- a/src/devices/Is31fl3730/samples/MicroDotPhat.csproj +++ b/src/devices/Is31fl3730/samples/MicroDotPhat.csproj @@ -1,7 +1,7 @@ Exe - $(DefaultBindingTfms) + net6.0 false From f0a1458311522a639dcf7e8794065c0bfd4c61e6 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Fri, 23 Sep 2022 20:40:54 -0700 Subject: [PATCH 05/46] Add Matrix5x7 class --- src/devices/Is31fl3730/Bonnet5x7x6.cs | 61 ++++++++ src/devices/Is31fl3730/Breakout5x7x2.cs | 62 ++++++++ src/devices/Is31fl3730/Is31fl3730.cs | 165 ++++++++++++++------- src/devices/Is31fl3730/Is31fl3730.csproj | 1 + src/devices/Is31fl3730/Matrix5x7.cs | 72 ++++++++++ src/devices/Is31fl3730/samples/Program.cs | 168 ++++++++++++++++++++-- 6 files changed, 469 insertions(+), 60 deletions(-) create mode 100644 src/devices/Is31fl3730/Bonnet5x7x6.cs create mode 100644 src/devices/Is31fl3730/Breakout5x7x2.cs create mode 100644 src/devices/Is31fl3730/Matrix5x7.cs diff --git a/src/devices/Is31fl3730/Bonnet5x7x6.cs b/src/devices/Is31fl3730/Bonnet5x7x6.cs new file mode 100644 index 0000000000..14b182282d --- /dev/null +++ b/src/devices/Is31fl3730/Bonnet5x7x6.cs @@ -0,0 +1,61 @@ +// 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.I2c; +using System.Threading; + +namespace Iot.Device.Display +{ + /// + /// Represents LED Dot Matrix Breakout + /// + // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf + // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout + // Related repo: https://github.com/pimoroni/microdot-phat + public class Matrix5x7 : IDisposable + { + private readonly Is31fl3730 _is31fl3730; + + /// + /// Initialize IS31FL3730 device + /// + /// The to create with. + /// The width of the LED matrix. + /// The height of the LED matrix. + public Matrix5x7(Is31fl3730 is31fl3730, int width, int height, int matrix) + { + _is31fl3730 = is31fl3730; + Width = width; + Height = height; + Matrix = matrix; + } + + /// + /// Indexer for matrix. + /// + public int this[int x, int y] + { + get => _is31fl3730.ReadLed(Matrix, x, y); + set => _is31fl3730.WriteLed(Matrix, x, y, value); + } + + public static readonly int DefaultI2cAddress = 0x61; + + /// + /// Width of LED matrix (x axis). + /// + public readonly int Width = 5; + + /// + /// Height of LED matrix (y axis). + /// + public readonly int Height = 7; + + /// + /// Identification of matrix (of 2). + /// + public readonly int Matrix = 0; + } +} diff --git a/src/devices/Is31fl3730/Breakout5x7x2.cs b/src/devices/Is31fl3730/Breakout5x7x2.cs new file mode 100644 index 0000000000..2f4a82045c --- /dev/null +++ b/src/devices/Is31fl3730/Breakout5x7x2.cs @@ -0,0 +1,62 @@ +// 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.I2c; +using System.Threading; + +namespace Iot.Device.Display +{ + /// + /// Represents an IS31FL3731 LED Matrix driver + /// + // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf + // Product: https://shop.pimoroni.com/products/microdot-phat + // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout + // Related repo: https://github.com/pimoroni/microdot-phat + public class Matrix5x7 : IDisposable + { + private readonly Is31fl3730 _is31fl3730; + + /// + /// Initialize IS31FL3730 device + /// + /// The to create with. + /// The width of the LED matrix. + /// The height of the LED matrix. + public Matrix5x7(Is31fl3730 is31fl3730, int width, int height, int matrix) + { + _is31fl3730 = is31fl3730; + Width = width; + Height = height; + Matrix = matrix; + } + + /// + /// Indexer for matrix. + /// + public int this[int x, int y] + { + get => _is31fl3730.ReadLed(Matrix, x, y); + set => _is31fl3730.WriteLed(Matrix, x, y, value); + } + + public static readonly int DefaultI2cAddress = 0x61; + + /// + /// Width of LED matrix (x axis). + /// + public readonly int Width = 5; + + /// + /// Height of LED matrix (y axis). + /// + public readonly int Height = 7; + + /// + /// Identification of matrix (of 2). + /// + public readonly int Matrix = 0; + } +} diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index b1b94cf48e..e58817fb0c 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -39,29 +39,28 @@ public class Is31fl3730 : IDisposable private const byte MATRIX_5x11 = 0x3; // Values + private readonly byte[] _matrix_registers = new byte[] { MATRIX_1_REGISTER, MATRIX_2_REGISTER }; private readonly byte[] _disable_all_leds_data = new byte[8]; private readonly byte[] _enable_all_leds_data = new byte[8]; - private byte[] _matrix1 = new byte[8]; - private byte[] _matrix2 = new byte[8]; + private readonly Matrix5x7?[] _matrices = new Matrix5x7[2]; + private readonly List _buffers = new List(2); private I2cDevice _i2cDevice; + private byte[] _buffer1 = new byte[8]; + private byte[] _buffer2 = new byte[8]; + private bool _matrix1Enabled = true; + private bool _matrix2Enabled = false; private int _configurationValue = 0; - /// + /// /// Initialize IS31FL3730 device /// /// The to create with. public Is31fl3730(I2cDevice i2cDevice) { _i2cDevice = i2cDevice; - // _enable_all_leds_data.AsSpan().Fill(0xff); - _enable_all_leds_data[0] = 37; - _enable_all_leds_data[1] = 127; - _enable_all_leds_data[2] = 127; - _enable_all_leds_data[3] = 127; - _enable_all_leds_data[4] = 0; - _enable_all_leds_data[5] = 0; - _enable_all_leds_data[6] = 16; - _enable_all_leds_data[7] = 64; + _enable_all_leds_data.AsSpan().Fill(0xff); + _buffers.Add(_buffer1); + _buffers.Add(_buffer2); } /// @@ -77,50 +76,56 @@ public Is31fl3730(I2cDevice i2cDevice, int width, int height) Height = height; } - /// - /// Default I2C address for device. - /// /* The Pimoroni devices support three I2C devices: - + - 0x61 (the default) - 0x62 - 0x63 - + For the breakout, this is straightforward. There is a default and you can change the address (in the normal way). For the Micro Dot pHAT, there are three pairs installed (making six matrices). The addresses are ordered this way: - x63 x62 x61 + x63 x62 x61 ________ _________ ________ m2 | m1 || m2 | m1 || m2 | m1 This ordering makes sense if you are scrolling content right to left. - More detailed information about the structure of each pair follows (later in doc). + More detailed information about the structure of each pair follows (further down). */ + + /// + /// Default I2C address for device. + /// public static readonly int DefaultI2cAddress = 0x61; /// /// Width of LED matrix (x axis). /// - public readonly int Width = 16; + public readonly int Width = 5; /// /// Height of LED matrix (y axis). /// - public readonly int Height = 9; + public readonly int Height = 7; /// /// Brightness of LED matrix (override default value (40 mA); set before calling Initialize method). /// - public int Brightness = 128; + public int Brightness = 0; /// /// Full current setting for each row output of LED matrix (override default value (128; max brightness); set before calling Initialize method). /// - public int CurrentSetting = 0b00001110; + public int CurrentSetting = 0; + + /// + /// Indexer for matrix. + /// + public Matrix5x7? this[int matrix] => _matrices[matrix]; /// /// Initialize LED driver. @@ -141,15 +146,29 @@ public void Initialize() { _i2cDevice.Write(new byte[] { PWM_REGISTER, (byte)Brightness }); } + + _matrices[0] = _matrix1Enabled ? new Matrix5x7(this, 0) : null; + _matrices[1] = _matrix2Enabled ? new Matrix5x7(this, 1) : null; } /// - /// Indexer for updating matrix, with PWM register. + /// Fill all LEDS. /// - public int this[int matrix, int x, int y] + public void Fill(int matrix, int value) { - // get => ReadLedPwm(x, y); - set => WriteLed(matrix, x, y, value); + byte[] buffer = _buffers[matrix]; + + if (value > 0) + { + buffer.AsSpan().Fill(255); + } + else + { + buffer.AsSpan().Fill(0); + } + + Write(_matrix_registers[matrix], _buffer1); + WriteUpdateRegister(); } /// @@ -157,8 +176,16 @@ public void Initialize() /// public void EnableAllLeds() { - Write(MATRIX_1_REGISTER, _enable_all_leds_data); - // Write(MATRIX_2_REGISTER, _enable_all_leds_data); + if (_matrix1Enabled) + { + Write(MATRIX_1_REGISTER, _enable_all_leds_data); + } + + if (_matrix2Enabled) + { + Write(MATRIX_2_REGISTER, _enable_all_leds_data); + } + WriteUpdateRegister(); } @@ -167,8 +194,16 @@ public void EnableAllLeds() /// public void DisableAllLeds() { - Write(MATRIX_1_REGISTER, _disable_all_leds_data); - Write(MATRIX_2_REGISTER, _disable_all_leds_data); + if (_matrix1Enabled) + { + Write(MATRIX_1_REGISTER, _disable_all_leds_data); + } + + if (_matrix2Enabled) + { + Write(MATRIX_2_REGISTER, _disable_all_leds_data); + } + WriteUpdateRegister(); } @@ -177,6 +212,9 @@ public void DisableAllLeds() /// public void SetDisplayMode(bool matrixOne, bool matrixTwo) { + _matrix1Enabled = matrixOne; + _matrix2Enabled = matrixTwo; + _configurationValue |= (matrixOne, matrixTwo) switch { (true, true) => DISPLAY_MATRIX_BOTH, @@ -258,7 +296,7 @@ private void Write(byte address, byte value) _i2cDevice.Write(new byte[] { address, value }); } - private void WriteLed(int matrix, int x, int y, int enable) + internal void WriteLed(int matrix, int x, int y, int enable) { /* The following diagrams and information demonstrate how the matrix is structured. @@ -306,7 +344,12 @@ x x xxxxx | xxxxx xxxxx | xxxxx x x - *matrix 1* + *matrix 1* + + If you write two bytes, then you'll write to the first two rows or + columns, respectively. With the matrix two, you can only write 5 bytes + and with matrix one, you can write 7, however, the number of bits that + are used differs. Straightforwardly, both matrices start in the top-left, however matrix 1 is row-based, left to right and matrix 2 is column-based @@ -314,7 +357,7 @@ x x You will notice these matrices are not symmetrical when you consider rows vs columns. Theses matrices are 5x7 not 5x5 or 7x7. - + That means that writing a byte -- 1000_0000 -- with just the high bit set won't do anything for either matrix since that bit effectively "falls off". @@ -324,6 +367,19 @@ x x correct bit, one at a time, either row- or column-based (as you see in the code below). + There are those extra pixels at the bottom, one per matrix. They are addressed + in the following way. Assume, you have a buffer defined like: + + byte[] buffer = new byte[8] + + To set the extra pixel, ensure the following bit is set: + + - For Matrix 1: buffer[6] = 128; + - For Matrix 2: buffer[7] = 64; + + buffer[6] is also used for the 7th row, on matrix 1. If you want to light up all + pixels and the special pixel, then set that buffer value to 159. That's all the bits but two of the highest ones (32 and 64). + If you have a bitmap you want to write all at once, then you can simply write rows of bytes to matrix 1. However, you need to ensure your bitmap only uses the first 5 bits. If you are writing to matrix 2 then writing one row at a @@ -332,21 +388,14 @@ x x translate row-based content to columns, similar to the `else` clause below. Separately, you can disable one matrix or the other. That's largely a separate - concern. It has nothing to do with byte structure. - + concern. It has nothing to do with byte structure. */ - if (matrix is 0) - { - byte mask = (byte)(1 << x); - _matrix1[y] = UpdateByte(_matrix1[y], mask, enable); - } - else if (matrix is 1) - { - byte mask = (byte)(1 << y); - _matrix2[x] = UpdateByte(_matrix2[x], mask, enable); - - } + int row = matrix is 0 ? y : x; + int column = matrix is 0 ? x : y; + byte mask = (byte)(1 << column); + byte[] m = _buffers[matrix]; + m[row] = UpdateByte(m[row], mask, enable); UpdateMatrixRegisters(); } @@ -365,6 +414,16 @@ private byte UpdateByte(byte data, byte mask, int enable) return data; } + internal int ReadLed(int matrix, int x, int y) + { + int row = matrix is 0 ? y : x; + int column = matrix is 0 ? x : y; + int mask = 1 << column; + byte[] m = _buffers[matrix]; + int r = m[row]; + return r & mask; + } + private void WriteUpdateRegister() { Write(UPDATE_COLUMN_REGISTER, 0x80); @@ -372,8 +431,16 @@ private void WriteUpdateRegister() private void UpdateMatrixRegisters() { - Write(MATRIX_1_REGISTER, _matrix1); - Write(MATRIX_2_REGISTER, _matrix2); + if (_matrix1Enabled) + { + Write(MATRIX_1_REGISTER, _buffer1); + } + + if (_matrix2Enabled) + { + Write(MATRIX_2_REGISTER, _buffer2); + } + WriteUpdateRegister(); } } diff --git a/src/devices/Is31fl3730/Is31fl3730.csproj b/src/devices/Is31fl3730/Is31fl3730.csproj index dee6da6145..019c0cd188 100644 --- a/src/devices/Is31fl3730/Is31fl3730.csproj +++ b/src/devices/Is31fl3730/Is31fl3730.csproj @@ -5,6 +5,7 @@ + \ No newline at end of file diff --git a/src/devices/Is31fl3730/Matrix5x7.cs b/src/devices/Is31fl3730/Matrix5x7.cs new file mode 100644 index 0000000000..8b0482d0a9 --- /dev/null +++ b/src/devices/Is31fl3730/Matrix5x7.cs @@ -0,0 +1,72 @@ +// 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.I2c; +using System.Threading; + +namespace Iot.Device.Display +{ + /// + /// Represents LED Dot Matrix Breakout + /// + // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf + // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout + // Related repo: https://github.com/pimoroni/microdot-phat + public class Matrix5x7 + { + private readonly Is31fl3730 _is31fl3730; + + /// + /// Initialize IS31FL3730 device + /// + /// The to create with. + /// The index of the matrix (of a pair). + public Matrix5x7(Is31fl3730 is31fl3730, int matrix) + { + _is31fl3730 = is31fl3730; + Width = _is31fl3730.Width; + Height = _is31fl3730.Height; + Matrix = matrix; + } + + /// + /// Indexer for matrix. + /// + public int this[int x, int y] + { + get => _is31fl3730.ReadLed(Matrix, x, y); + set => _is31fl3730.WriteLed(Matrix, x, y, value); + } + + /// + /// Default I2C address for device. + /// + public static readonly int DefaultI2cAddress = 0x61; + + /// + /// Width of LED matrix (x axis). + /// + public readonly int Width = 5; + + /// + /// Height of LED matrix (y axis). + /// + public readonly int Height = 7; + + /// + /// Identification of matrix (of 2). + /// + public readonly int Matrix = 0; + + /// + /// Identification of matrix (of 2). + /// + public void Fill(int value) + { + _is31fl3730.Fill(Matrix, value); + } + + } +} diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index deccd574ef..5e0ac40cfb 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -2,20 +2,166 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Device.I2c; +using System.Linq; using System.Threading; using Iot.Device.Display; -using Is31fl3730 matrix = new(I2cDevice.Create(new I2cConnectionSettings(busId: 1, Is31fl3730.DefaultI2cAddress))); +using Is31fl3730 m = new(I2cDevice.Create(new I2cConnectionSettings(busId: 1, Is31fl3730.DefaultI2cAddress))); -// matrix.Brightness = 127; -matrix.Initialize(); -matrix.DisableAllLeds(); +m.SetDisplayMode(true, true); +m.Initialize(); +m.DisableAllLeds(); Thread.Sleep(100); -matrix.EnableAllLeds(); -// Thread.Sleep(100); -// matrix[0, 4, 3] = 1; -// matrix[0, 4, 4] = 1; -// matrix[0, 4, 5] = 1; -// matrix[0, 4, 6] = 1; -// matrix[0, 0, 7] = 1; +var mOne = m[0]; +var mTwo = m[1]; + +if (mOne is null || mTwo is null) +{ + return; +} + +var matrix = mTwo; + +// Dimensions +int width = matrix.Width - 1; +int height = matrix.Height - 1; +int halfWidth = matrix.Width / 2; +int halfHeight = matrix.Height / 2; + +matrix[0, 0] = 1; +matrix[0, height] = 1; +matrix[width, 0] = 1; +matrix[width, height] = 1; + +Thread.Sleep(500); +matrix.Fill(0); + +// Set pixel in the origin 0, 0 position. +matrix[0, 0] = 1; +// Set pixels in the middle +matrix[halfWidth - 1, halfHeight - 1] = 1; +matrix[halfWidth - 1, halfHeight] = 1; +matrix[halfWidth, halfHeight - 1] = 1; +matrix[halfWidth, halfHeight] = 1; +// Set pixel on the opposite edge +matrix[width - 1, height - 1] = 1; +matrix[width - 1, height] = 1; +matrix[width, height - 1] = 1; +matrix[width, height] = 1; + +Thread.Sleep(500); +matrix.Fill(0); + +// Draw line in first row +for (int i = 0; i < matrix.Width; i++) +{ + if (i % 2 is 1) + { + continue; + } + + matrix[i, 0] = 1; + Thread.Sleep(50); +} + +// Draw line in last row +for (int i = 0; i < matrix.Width; i++) +{ + if (i % 2 is 0) + { + continue; + } + + matrix[i, height] = 1; + Thread.Sleep(50); +} + +Thread.Sleep(500); +matrix.Fill(0); + +int diagonal = Math.Min(height, width); + +// Draw diagonal lines +for (int i = 0; i <= diagonal; i++) +{ + matrix[i, i] = 1; + matrix[diagonal - i, i] = 1; + Thread.Sleep(50); +} + +for (int i = 0; i <= diagonal; i++) +{ + matrix[i, i] = 0; + matrix[diagonal - i, i] = 0; + Thread.Sleep(50); +} + +// Draw a bounding box +for (int i = 0; i < matrix.Width; i++) +{ + matrix[i, 0] = 1; + Thread.Sleep(10); +} + +for (int i = 0; i < matrix.Height; i++) +{ + matrix[width, i] = 1; + Thread.Sleep(10); +} + +for (int i = width; i >= 0; i--) +{ + matrix[i, height] = 1; + Thread.Sleep(10); +} + +for (int i = height; i >= 0; i--) +{ + matrix[0, i] = 1; + Thread.Sleep(50); +} + +Thread.Sleep(500); +matrix.Fill(0); + +void WriteRowPixels(int row, IEnumerable pixels, int value) +{ + foreach (int pixel in pixels) + { + matrix[pixel, row] = (byte)value; + Thread.Sleep(15); + } +} + +void WriteColumnPixels(int column, IEnumerable pixels, int value) +{ + foreach (int pixel in pixels) + { + matrix[column, pixel] = (byte)value; + Thread.Sleep(15); + } +} + +// Draw a spiral bounding box +int iterations = (int)(Math.Ceiling(diagonal / 2.0) + 1); +for (int j = 0; j < iterations; j++) +{ + int rangeW = matrix.Width - j * 2; + int rangeH = matrix.Height - j * 2; + // top + WriteRowPixels(j, Enumerable.Range(j, rangeW), 1); + + // right + WriteColumnPixels(width - j, Enumerable.Range(j + 1, rangeH - 1), 1); + + // bottom + WriteRowPixels(height - j, Enumerable.Range(j, rangeW).Reverse(), 1); + + // left + WriteColumnPixels(j, Enumerable.Range(j + 1, rangeH - 1).Reverse(), 1); +} + +Thread.Sleep(1000); +matrix.Fill(0); From 1c6130a7f24be6edb9b77a1380500205dac85636 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 28 Sep 2022 20:36:40 -0700 Subject: [PATCH 06/46] Add higher-level bindings --- src/devices/Is31fl3730/Breakout5x7x2.cs | 62 ---- src/devices/Is31fl3730/BreakoutPair5x7.cs | 95 +++++ src/devices/Is31fl3730/Current.cs | 48 +++ src/devices/Is31fl3730/DisplayMode.cs | 33 ++ src/devices/Is31fl3730/Is31fl3730.cs | 338 +++++++----------- src/devices/Is31fl3730/Is31fl3730.csproj | 5 +- .../{Matrix5x7.cs => Matrix3730.cs} | 27 +- src/devices/Is31fl3730/samples/Program.cs | 12 +- 8 files changed, 332 insertions(+), 288 deletions(-) delete mode 100644 src/devices/Is31fl3730/Breakout5x7x2.cs create mode 100644 src/devices/Is31fl3730/BreakoutPair5x7.cs create mode 100644 src/devices/Is31fl3730/Current.cs create mode 100644 src/devices/Is31fl3730/DisplayMode.cs rename src/devices/Is31fl3730/{Matrix5x7.cs => Matrix3730.cs} (68%) diff --git a/src/devices/Is31fl3730/Breakout5x7x2.cs b/src/devices/Is31fl3730/Breakout5x7x2.cs deleted file mode 100644 index 2f4a82045c..0000000000 --- a/src/devices/Is31fl3730/Breakout5x7x2.cs +++ /dev/null @@ -1,62 +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.I2c; -using System.Threading; - -namespace Iot.Device.Display -{ - /// - /// Represents an IS31FL3731 LED Matrix driver - /// - // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf - // Product: https://shop.pimoroni.com/products/microdot-phat - // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout - // Related repo: https://github.com/pimoroni/microdot-phat - public class Matrix5x7 : IDisposable - { - private readonly Is31fl3730 _is31fl3730; - - /// - /// Initialize IS31FL3730 device - /// - /// The to create with. - /// The width of the LED matrix. - /// The height of the LED matrix. - public Matrix5x7(Is31fl3730 is31fl3730, int width, int height, int matrix) - { - _is31fl3730 = is31fl3730; - Width = width; - Height = height; - Matrix = matrix; - } - - /// - /// Indexer for matrix. - /// - public int this[int x, int y] - { - get => _is31fl3730.ReadLed(Matrix, x, y); - set => _is31fl3730.WriteLed(Matrix, x, y, value); - } - - public static readonly int DefaultI2cAddress = 0x61; - - /// - /// Width of LED matrix (x axis). - /// - public readonly int Width = 5; - - /// - /// Height of LED matrix (y axis). - /// - public readonly int Height = 7; - - /// - /// Identification of matrix (of 2). - /// - public readonly int Matrix = 0; - } -} diff --git a/src/devices/Is31fl3730/BreakoutPair5x7.cs b/src/devices/Is31fl3730/BreakoutPair5x7.cs new file mode 100644 index 0000000000..9643866b13 --- /dev/null +++ b/src/devices/Is31fl3730/BreakoutPair5x7.cs @@ -0,0 +1,95 @@ +// 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.I2c; +using System.Threading; + +namespace Iot.Device.Display +{ + /// + /// Represents an IS31FL3731 LED Matrix driver + /// + // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf + // Product: https://shop.pimoroni.com/products/microdot-phat + // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout + // Related repo: https://github.com/pimoroni/microdot-phat + public class BreakoutPair5x7 : IDisposable + { + private readonly Matrix3730 _matrixOne; + private readonly Matrix3730 _matrixTwo; + private readonly Matrix3730[] _pair = new Matrix3730[2]; + private Is31fl3730 _is31fl3730; + private I2cDevice? _i2cDevice; + + /// + /// Initialize IS31FL3730 device + /// + /// The to create with. + public BreakoutPair5x7(I2cDevice? i2cDevice = null) + { + _i2cDevice = i2cDevice is not null ? i2cDevice : I2cDevice.Create(new(1, Is31fl3730.DefaultI2cAddress)); + _is31fl3730 = new(_i2cDevice); + _is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; + _is31fl3730.Initialize(); + _matrixOne = new Matrix3730(_is31fl3730, 0); + _matrixTwo = new Matrix3730(_is31fl3730, 1); + _pair = new Matrix3730[] { _matrixOne, _matrixTwo }; + } + + /// + /// Initialize IS31FL3730 device + /// + /// The to create with. + public BreakoutPair5x7(Is31fl3730 is31fl3730) + { + _is31fl3730 = is31fl3730; + _matrixOne = new Matrix3730(_is31fl3730, 0); + _matrixTwo = new Matrix3730(_is31fl3730, 1); + _pair = new Matrix3730[] { _matrixOne, _matrixTwo }; + } + + /// + /// Indexer for matrix pair. + /// + public Matrix3730 this[int matrix] + { + get => _pair[matrix]; + } + + /// + /// Default I2C address for device. + /// + public static readonly int DefaultI2cAddress = 0x61; + + /// + /// Width of LED matrix (x axis). + /// + public readonly int Width = 10; + + /// + /// Height of LED matrix (y axis). + /// + public readonly int Height = 7; + + /// + /// Identification of matrix (of 2). + /// + public readonly int Matrix = 0; + + /// + /// Fill All LEDs. + /// + public void Fill(int value) => _is31fl3730.FillAll(value); + + /// + public void Dispose() + { + _is31fl3730?.Dispose(); + _is31fl3730 = null!; + _i2cDevice?.Dispose(); + _i2cDevice = null!; + } + } +} diff --git a/src/devices/Is31fl3730/Current.cs b/src/devices/Is31fl3730/Current.cs new file mode 100644 index 0000000000..4852a2fa22 --- /dev/null +++ b/src/devices/Is31fl3730/Current.cs @@ -0,0 +1,48 @@ +// 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.Threading; +using System.Threading.Tasks; +using System.Device.Gpio; +using System.Device.Spi; +using Iot.Device.Multiplexing.Utility; + +namespace Iot.Device.Display +{ + /// + /// Represents an IS31FL3731 LED Matrix driver + /// + public enum Current + { + /// + /// 5 mA + /// + MA5 = 0b1000, + + /// + /// 10 mA + /// + MA10 = 0b1001, + + /// + /// 35 mA + /// + MA35 = 0b1110, + + /// + /// 10 mA + /// + MA40 = 0b0, + + /// + /// 10 mA + /// + MA45 = 0b0001, + + /// + /// 40 mA + /// + MA75 = 0b0111, + } +} diff --git a/src/devices/Is31fl3730/DisplayMode.cs b/src/devices/Is31fl3730/DisplayMode.cs new file mode 100644 index 0000000000..894cbfe44d --- /dev/null +++ b/src/devices/Is31fl3730/DisplayMode.cs @@ -0,0 +1,33 @@ +// 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.Threading; +using System.Threading.Tasks; +using System.Device.Gpio; +using System.Device.Spi; +using Iot.Device.Multiplexing.Utility; + +namespace Iot.Device.Display +{ + /// + /// Represents an IS31FL3731 LED Matrix driver + /// + public enum DisplayMode + { + /// + /// Enable matrix one only. + /// + MatrixOneOnly = 0x0, + + /// + /// Enable matrix two only. + /// + MatrixTwoOnly = 0x8, + + /// + /// Enable matrix one and two. + /// + MatrixOneAndTwo = 0x18, + } +} diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index e58817fb0c..a2b95c61fe 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -22,6 +22,7 @@ public class Is31fl3730 : IDisposable private const byte CONFIGURATION_REGISTER = 0x0; private const byte MATRIX_1_REGISTER = 0x1; private const byte MATRIX_2_REGISTER = 0x0E; + private const int MATRIX_REGISTER_LENGTH = 8; private const byte UPDATE_COLUMN_REGISTER = 0x0C; private const byte LIGHTING_EFFECT_REGISTER = 0x0D; private const byte PWM_REGISTER = 0x19; @@ -30,19 +31,12 @@ public class Is31fl3730 : IDisposable // Configuration register // table 3 in datasheet private const byte SHUTDOWN = 0x80; - private const byte DISPLAY_MATRIX_ONE = 0x0; - private const byte DISPLAY_MATRIX_TWO = 0x8; - private const byte DISPLAY_MATRIX_BOTH = 0x18; - private const byte MATRIX_8x8 = 0x0; - private const byte MATRIX_7x9 = 0x1; - private const byte MATRIX_6x10 = 0x2; - private const byte MATRIX_5x11 = 0x3; // Values + private const byte EIGHT_BIT_VALUE = 0x80; private readonly byte[] _matrix_registers = new byte[] { MATRIX_1_REGISTER, MATRIX_2_REGISTER }; - private readonly byte[] _disable_all_leds_data = new byte[8]; - private readonly byte[] _enable_all_leds_data = new byte[8]; - private readonly Matrix5x7?[] _matrices = new Matrix5x7[2]; + private readonly byte[] _disable_all_leds_data = new byte[MATRIX_REGISTER_LENGTH]; + private readonly byte[] _enable_all_leds_data = new byte[MATRIX_REGISTER_LENGTH]; private readonly List _buffers = new List(2); private I2cDevice _i2cDevice; private byte[] _buffer1 = new byte[8]; @@ -63,19 +57,6 @@ public Is31fl3730(I2cDevice i2cDevice) _buffers.Add(_buffer2); } - /// - /// Initialize IS31FL3730 device - /// - /// The to create with. - /// The width of the LED matrix. - /// The height of the LED matrix. - public Is31fl3730(I2cDevice i2cDevice, int width, int height) - : this(i2cDevice) - { - Width = width; - Height = height; - } - /* The Pimoroni devices support three I2C devices: @@ -103,200 +84,71 @@ public Is31fl3730(I2cDevice i2cDevice, int width, int height) public static readonly int DefaultI2cAddress = 0x61; /// - /// Width of LED matrix (x axis). + /// Supported I2C addresses for device. /// - public readonly int Width = 5; + public static readonly int[] SupportedI2cAddresses = new int[] { DefaultI2cAddress, 0x62, 0x63 }; /// - /// Height of LED matrix (y axis). + /// Brightness of LED matrix (override default value (128; max brightness)); set before calling Initialize method). /// - public readonly int Height = 7; + public int Brightness = 0; /// - /// Brightness of LED matrix (override default value (40 mA); set before calling Initialize method). + /// Full current setting for each row output of LED matrix (override default value (40 mA)); set before calling Initialize method). /// - public int Brightness = 0; + public Current Current = 0; /// - /// Full current setting for each row output of LED matrix (override default value (128; max brightness); set before calling Initialize method). + /// Matrix mode (override default value (8x8); set before calling Initialize method). /// - public int CurrentSetting = 0; + public MatrixMode MatrixMode = 0; /// - /// Indexer for matrix. + /// Display mode (override default value (Matrix 1 only); set before calling Initialize method). /// - public Matrix5x7? this[int matrix] => _matrices[matrix]; + public DisplayMode DisplayMode = 0; /// /// Initialize LED driver. /// public void Initialize() { - if (_configurationValue > 0) + if (MatrixMode > 0) { - WriteConfiguration(); + _configurationValue |= (int)MatrixMode; } - if (CurrentSetting > 0) + if (DisplayMode > 0) { - _i2cDevice.Write(new byte[] { LIGHTING_EFFECT_REGISTER, (byte)CurrentSetting }); + _matrix1Enabled = DisplayMode is DisplayMode.MatrixOneOnly or DisplayMode.MatrixOneAndTwo; + _matrix2Enabled = DisplayMode is DisplayMode.MatrixTwoOnly or DisplayMode.MatrixOneAndTwo; + _configurationValue |= (int)DisplayMode; } - if (Brightness > 0) - { - _i2cDevice.Write(new byte[] { PWM_REGISTER, (byte)Brightness }); - } - - _matrices[0] = _matrix1Enabled ? new Matrix5x7(this, 0) : null; - _matrices[1] = _matrix2Enabled ? new Matrix5x7(this, 1) : null; - } - - /// - /// Fill all LEDS. - /// - public void Fill(int matrix, int value) - { - byte[] buffer = _buffers[matrix]; - - if (value > 0) - { - buffer.AsSpan().Fill(255); - } - else - { - buffer.AsSpan().Fill(0); - } - - Write(_matrix_registers[matrix], _buffer1); - WriteUpdateRegister(); - } - - /// - /// Enable all LEDs. - /// - public void EnableAllLeds() - { - if (_matrix1Enabled) - { - Write(MATRIX_1_REGISTER, _enable_all_leds_data); - } - - if (_matrix2Enabled) + if (_configurationValue > 0) { - Write(MATRIX_2_REGISTER, _enable_all_leds_data); + Write(CONFIGURATION_REGISTER, (byte)_configurationValue); } - WriteUpdateRegister(); - } - - /// - /// Disable all LEDs. - /// - public void DisableAllLeds() - { - if (_matrix1Enabled) + if (Current > 0) { - Write(MATRIX_1_REGISTER, _disable_all_leds_data); + Write(LIGHTING_EFFECT_REGISTER, (byte)Current); } - if (_matrix2Enabled) + if (Brightness > 0) { - Write(MATRIX_2_REGISTER, _disable_all_leds_data); + Write(PWM_REGISTER, (byte)Brightness); } - - WriteUpdateRegister(); } /// - /// Set display mode. Call before Initialize method. + /// Write LED for matrix. /// - public void SetDisplayMode(bool matrixOne, bool matrixTwo) - { - _matrix1Enabled = matrixOne; - _matrix2Enabled = matrixTwo; - - _configurationValue |= (matrixOne, matrixTwo) switch - { - (true, true) => DISPLAY_MATRIX_BOTH, - (true, _) => DISPLAY_MATRIX_ONE, - (_, true) => DISPLAY_MATRIX_TWO, - _ => throw new Exception("Invalid input.") - }; - } - - /// - /// Set matrix mode. Call before Initialize method. - /// - public void SetMatrixMode(MatrixMode mode) - { - _configurationValue |= mode switch - { - MatrixMode.Size5x11 => MATRIX_5x11, - MatrixMode.Size6x10 => MATRIX_6x10, - MatrixMode.Size7x9 => MATRIX_7x9, - MatrixMode.Size8x8 => MATRIX_8x8, - _ => throw new Exception("Invalid input.") - }; - } - - /// - /// Reset device. - /// - public void Reset() - { - // Reset device - Shutdown(true); - Thread.Sleep(10); - Shutdown(false); - } - - /// - /// Set the shutdown mode. - /// - /// Set the showdown mode. `true` sets device into shutdown mode. `false` sets device into normal operation. - public void Shutdown(bool shutdown) - { - // mode values - // 0 = normal operation - // 1 = shutdown mode - if (shutdown) - { - _configurationValue |= SHUTDOWN; - } - else - { - _configurationValue &= ~SHUTDOWN; - } - - WriteUpdateRegister(); - } - - /// - public void Dispose() - { - _i2cDevice?.Dispose(); - _i2cDevice = null!; - } - - private void WriteConfiguration() - { - Write(CONFIGURATION_REGISTER, (byte)_configurationValue); - } - - private void Write(byte address, byte[] value) - { - byte[] data = new byte[value.Length + 1]; - data[0] = address; - value.CopyTo(data.AsSpan(1)); - _i2cDevice.Write(data); - } - - private void Write(byte address, byte value) - { - _i2cDevice.Write(new byte[] { address, value }); - } - - internal void WriteLed(int matrix, int x, int y, int enable) + /// The matrix to use. + /// The x dimension for the LED. + /// The y dimension for the LED. + /// The value to write. + public void WriteLed(int matrix, int x, int y, int value) { /* The following diagrams and information demonstrate how the matrix is structured. @@ -391,57 +243,143 @@ x x concern. It has nothing to do with byte structure. */ + int logicalRow = matrix is 0 ? y : x; + int logicalColumn = matrix is 0 ? x : y; + byte mask = (byte)(1 << logicalColumn); + byte[] buffer = _buffers[matrix]; + buffer[logicalRow] = UpdateByte(buffer[logicalRow], mask, value); + + UpdateMatrixRegister(matrix); + } + + /// + /// Read value of LED for matrix. + /// + /// The matrix to use. + /// The x dimension for the LED. + /// The y dimension for the LED. + public int ReadLed(int matrix, int x, int y) + { int row = matrix is 0 ? y : x; int column = matrix is 0 ? x : y; - byte mask = (byte)(1 << column); + int mask = 1 << column; byte[] m = _buffers[matrix]; - m[row] = UpdateByte(m[row], mask, enable); + int r = m[row]; + return r & mask; + } - UpdateMatrixRegisters(); + /// + /// Update decimal point for matrix. + /// + public void UpdateDecimalPoint(int matrix, int value) + { + int matrixOneMask = 128; + int matrixtwoMask = 64; + + int mask = matrix is 0 ? matrixOneMask : matrixtwoMask; + int row = matrix is 0 ? 6 : 7; + byte[] buffer = _buffers[matrix]; + + buffer[row] = UpdateByte(buffer[row], (byte)mask, value); } - private byte UpdateByte(byte data, byte mask, int enable) + /// + /// Fill all LEDs with value. + /// + public void FillAll(int value) { - if (enable is 1) + if (_matrix1Enabled) { - data |= mask; + Fill(0, value); + } + + if (_matrix2Enabled) + { + Fill(1, value); + } + } + + /// + /// Fill all LEDs with value, per Matrix. + /// + public void Fill(int matrix, int value) + { + _buffers[matrix].AsSpan().Fill((byte)value); + UpdateMatrixRegister(matrix); + } + + /// + /// Reset device. + /// + public void Reset() => Write(RESET_REGISTER, EIGHT_BIT_VALUE); + + /// + /// Set the shutdown mode. + /// + /// Set the showdown mode. `true` sets device into shutdown mode. `false` sets device into normal operation. + public void Shutdown(bool shutdown) + { + // mode values + // 0 = normal operation + // 1 = shutdown mode + if (shutdown) + { + _configurationValue |= SHUTDOWN; } else { - data &= (byte)(~mask); + _configurationValue &= ~SHUTDOWN; } - return data; + WriteUpdateRegister(); } - internal int ReadLed(int matrix, int x, int y) + /// + public void Dispose() { - int row = matrix is 0 ? y : x; - int column = matrix is 0 ? x : y; - int mask = 1 << column; - byte[] m = _buffers[matrix]; - int r = m[row]; - return r & mask; + _i2cDevice?.Dispose(); + _i2cDevice = null!; } - private void WriteUpdateRegister() + private void Write(byte address, byte[] value) { - Write(UPDATE_COLUMN_REGISTER, 0x80); + byte[] data = new byte[value.Length + 1]; + data[0] = address; + value.CopyTo(data.AsSpan(1)); + _i2cDevice.Write(data); } - private void UpdateMatrixRegisters() + private void Write(byte address, byte value) => _i2cDevice.Write(new byte[] { address, value }); + + private byte UpdateByte(byte data, byte mask, int value) { - if (_matrix1Enabled) + if (value is 1) + { + data |= mask; + } + else + { + data &= (byte)(~mask); + } + + return data; + } + + private void UpdateMatrixRegister(int matrix) + { + if (matrix is 0 && _matrix1Enabled) { Write(MATRIX_1_REGISTER, _buffer1); } - if (_matrix2Enabled) + if (matrix is 1 && _matrix2Enabled) { Write(MATRIX_2_REGISTER, _buffer2); } WriteUpdateRegister(); } + + private void WriteUpdateRegister() => Write(UPDATE_COLUMN_REGISTER, EIGHT_BIT_VALUE); } } diff --git a/src/devices/Is31fl3730/Is31fl3730.csproj b/src/devices/Is31fl3730/Is31fl3730.csproj index 019c0cd188..32ca830ee1 100644 --- a/src/devices/Is31fl3730/Is31fl3730.csproj +++ b/src/devices/Is31fl3730/Is31fl3730.csproj @@ -4,8 +4,11 @@ false + + + - + \ No newline at end of file diff --git a/src/devices/Is31fl3730/Matrix5x7.cs b/src/devices/Is31fl3730/Matrix3730.cs similarity index 68% rename from src/devices/Is31fl3730/Matrix5x7.cs rename to src/devices/Is31fl3730/Matrix3730.cs index 8b0482d0a9..d527c05c70 100644 --- a/src/devices/Is31fl3730/Matrix5x7.cs +++ b/src/devices/Is31fl3730/Matrix3730.cs @@ -9,12 +9,9 @@ namespace Iot.Device.Display { /// - /// Represents LED Dot Matrix Breakout + /// Represents LED Dot Matrix driven by IS31FL3730. /// - // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf - // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout - // Related repo: https://github.com/pimoroni/microdot-phat - public class Matrix5x7 + public class Matrix3730 { private readonly Is31fl3730 _is31fl3730; @@ -23,11 +20,9 @@ public class Matrix5x7 /// /// The to create with. /// The index of the matrix (of a pair). - public Matrix5x7(Is31fl3730 is31fl3730, int matrix) + public Matrix3730(Is31fl3730 is31fl3730, int matrix) { _is31fl3730 = is31fl3730; - Width = _is31fl3730.Width; - Height = _is31fl3730.Height; Matrix = matrix; } @@ -40,11 +35,6 @@ public Matrix5x7(Is31fl3730 is31fl3730, int matrix) set => _is31fl3730.WriteLed(Matrix, x, y, value); } - /// - /// Default I2C address for device. - /// - public static readonly int DefaultI2cAddress = 0x61; - /// /// Width of LED matrix (x axis). /// @@ -61,12 +51,13 @@ public Matrix5x7(Is31fl3730 is31fl3730, int matrix) public readonly int Matrix = 0; /// - /// Identification of matrix (of 2). + /// Fill matrix (0 is dark; 1 is lit). /// - public void Fill(int value) - { - _is31fl3730.Fill(Matrix, value); - } + public void Fill(int value) => _is31fl3730.Fill(Matrix, value); + /// + /// Fill matrix (0 is dark; 1 is lit). + /// + public void UpdateDecimalPoint(int value) => _is31fl3730.UpdateDecimalPoint(Matrix, value); } } diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 5e0ac40cfb..ab00fdb6ee 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -8,21 +8,19 @@ using System.Threading; using Iot.Device.Display; -using Is31fl3730 m = new(I2cDevice.Create(new I2cConnectionSettings(busId: 1, Is31fl3730.DefaultI2cAddress))); +using BreakoutPair5x7 breakout = new(); -m.SetDisplayMode(true, true); -m.Initialize(); -m.DisableAllLeds(); +breakout.Fill(0); Thread.Sleep(100); -var mOne = m[0]; -var mTwo = m[1]; +var mOne = breakout[0]; +var mTwo = breakout[1]; if (mOne is null || mTwo is null) { return; } -var matrix = mTwo; +var matrix = mOne; // Dimensions int width = matrix.Width - 1; From c795dbf282b91975dffe0ba6b00bae06cc713ab5 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 28 Sep 2022 20:42:50 -0700 Subject: [PATCH 07/46] Rename sample project --- src/devices/Is31fl3730/samples/MicroDotPhat.csproj | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 src/devices/Is31fl3730/samples/MicroDotPhat.csproj diff --git a/src/devices/Is31fl3730/samples/MicroDotPhat.csproj b/src/devices/Is31fl3730/samples/MicroDotPhat.csproj deleted file mode 100644 index 9de2921e45..0000000000 --- a/src/devices/Is31fl3730/samples/MicroDotPhat.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - net6.0 - false - - - - - - \ No newline at end of file From b4c9e37047a16e62904ecfa7be2625b7000bcf60 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 28 Sep 2022 20:46:29 -0700 Subject: [PATCH 08/46] Rename sample project --- src/devices/Is31fl3730/Is31fl3730.cs | 1 + src/devices/Is31fl3730/samples/Matrix.samples.csproj | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 src/devices/Is31fl3730/samples/Matrix.samples.csproj diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index a2b95c61fe..aa6659e030 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -15,6 +15,7 @@ namespace Iot.Device.Display // Product: https://shop.pimoroni.com/products/microdot-phat // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat + // Based on: https://github.com/pimoroni/microdot-phat/blob/master/library/microdotphat/matrix.py public class Is31fl3730 : IDisposable { // Function register diff --git a/src/devices/Is31fl3730/samples/Matrix.samples.csproj b/src/devices/Is31fl3730/samples/Matrix.samples.csproj new file mode 100644 index 0000000000..9de2921e45 --- /dev/null +++ b/src/devices/Is31fl3730/samples/Matrix.samples.csproj @@ -0,0 +1,11 @@ + + + Exe + net6.0 + false + + + + + + \ No newline at end of file From 13a95a8fa00598cc6c7ad9f2a486aee14100e48d Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 28 Sep 2022 20:48:14 -0700 Subject: [PATCH 09/46] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/devices/Is31fl3730/Bonnet5x7x6.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/Is31fl3730/Bonnet5x7x6.cs b/src/devices/Is31fl3730/Bonnet5x7x6.cs index 14b182282d..1d4815a1b7 100644 --- a/src/devices/Is31fl3730/Bonnet5x7x6.cs +++ b/src/devices/Is31fl3730/Bonnet5x7x6.cs @@ -46,7 +46,7 @@ public Matrix5x7(Is31fl3730 is31fl3730, int width, int height, int matrix) /// /// Width of LED matrix (x axis). /// - public readonly int Width = 5; + public int Width { get; } = 5; /// /// Height of LED matrix (y axis). From bc4b4a453f37febb92651113010ea7e34bf3b8a5 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 28 Sep 2022 20:49:27 -0700 Subject: [PATCH 10/46] Update src/devices/Is31fl3730/Bonnet5x7x6.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/devices/Is31fl3730/Bonnet5x7x6.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/Is31fl3730/Bonnet5x7x6.cs b/src/devices/Is31fl3730/Bonnet5x7x6.cs index 1d4815a1b7..8fa1a231bd 100644 --- a/src/devices/Is31fl3730/Bonnet5x7x6.cs +++ b/src/devices/Is31fl3730/Bonnet5x7x6.cs @@ -41,7 +41,7 @@ public Matrix5x7(Is31fl3730 is31fl3730, int width, int height, int matrix) set => _is31fl3730.WriteLed(Matrix, x, y, value); } - public static readonly int DefaultI2cAddress = 0x61; + public const int DefaultI2cAddress = 0x61; /// /// Width of LED matrix (x axis). From 565fa6ec1ece375d3858789fe7e199570ea7018b Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Thu, 29 Sep 2022 13:16:27 -0700 Subject: [PATCH 11/46] Use lists/arrays more --- src/devices/Is31fl3730/Bonnet5x7x6.cs | 2 +- src/devices/Is31fl3730/BreakoutPair5x7.cs | 3 +- src/devices/Is31fl3730/Is31fl3730.cs | 55 +++++++++++------------ 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/devices/Is31fl3730/Bonnet5x7x6.cs b/src/devices/Is31fl3730/Bonnet5x7x6.cs index 8fa1a231bd..fb93e6dc47 100644 --- a/src/devices/Is31fl3730/Bonnet5x7x6.cs +++ b/src/devices/Is31fl3730/Bonnet5x7x6.cs @@ -46,7 +46,7 @@ public Matrix5x7(Is31fl3730 is31fl3730, int width, int height, int matrix) /// /// Width of LED matrix (x axis). /// - public int Width { get; } = 5; + public readonly int Width = 5; /// /// Height of LED matrix (y axis). diff --git a/src/devices/Is31fl3730/BreakoutPair5x7.cs b/src/devices/Is31fl3730/BreakoutPair5x7.cs index 9643866b13..ec75129e78 100644 --- a/src/devices/Is31fl3730/BreakoutPair5x7.cs +++ b/src/devices/Is31fl3730/BreakoutPair5x7.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections; using System.Collections.Generic; using System.Device.I2c; using System.Threading; @@ -61,7 +62,7 @@ public BreakoutPair5x7(Is31fl3730 is31fl3730) /// /// Default I2C address for device. /// - public static readonly int DefaultI2cAddress = 0x61; + public const int DefaultI2cAddress = 0x61; /// /// Width of LED matrix (x axis). diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index aa6659e030..ae39e692ce 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Device.I2c; using System.Threading; +using static System.Linq.Enumerable; namespace Iot.Device.Display { @@ -36,14 +37,9 @@ public class Is31fl3730 : IDisposable // Values private const byte EIGHT_BIT_VALUE = 0x80; private readonly byte[] _matrix_registers = new byte[] { MATRIX_1_REGISTER, MATRIX_2_REGISTER }; - private readonly byte[] _disable_all_leds_data = new byte[MATRIX_REGISTER_LENGTH]; - private readonly byte[] _enable_all_leds_data = new byte[MATRIX_REGISTER_LENGTH]; - private readonly List _buffers = new List(2); + private readonly List _buffers; + private readonly bool[] _enabled = new bool[2]; private I2cDevice _i2cDevice; - private byte[] _buffer1 = new byte[8]; - private byte[] _buffer2 = new byte[8]; - private bool _matrix1Enabled = true; - private bool _matrix2Enabled = false; private int _configurationValue = 0; /// @@ -53,9 +49,11 @@ public class Is31fl3730 : IDisposable public Is31fl3730(I2cDevice i2cDevice) { _i2cDevice = i2cDevice; - _enable_all_leds_data.AsSpan().Fill(0xff); - _buffers.Add(_buffer1); - _buffers.Add(_buffer2); + _buffers = new List() + { + new byte[8], + new byte[8] + }; } /* @@ -82,7 +80,7 @@ public Is31fl3730(I2cDevice i2cDevice) /// /// Default I2C address for device. /// - public static readonly int DefaultI2cAddress = 0x61; + public const int DefaultI2cAddress = 0x61; /// /// Supported I2C addresses for device. @@ -121,10 +119,14 @@ public void Initialize() if (DisplayMode > 0) { - _matrix1Enabled = DisplayMode is DisplayMode.MatrixOneOnly or DisplayMode.MatrixOneAndTwo; - _matrix2Enabled = DisplayMode is DisplayMode.MatrixTwoOnly or DisplayMode.MatrixOneAndTwo; + _enabled[0] = DisplayMode is DisplayMode.MatrixOneOnly or DisplayMode.MatrixOneAndTwo; + _enabled[1] = DisplayMode is DisplayMode.MatrixTwoOnly or DisplayMode.MatrixOneAndTwo; _configurationValue |= (int)DisplayMode; } + else + { + _enabled[0] = true; + } if (_configurationValue > 0) { @@ -289,14 +291,12 @@ public void UpdateDecimalPoint(int matrix, int value) /// public void FillAll(int value) { - if (_matrix1Enabled) - { - Fill(0, value); - } - - if (_matrix2Enabled) + foreach (int i in Range(0, 2)) { - Fill(1, value); + if (_enabled[i]) + { + Fill(i, value); + } } } @@ -344,13 +344,13 @@ public void Dispose() private void Write(byte address, byte[] value) { - byte[] data = new byte[value.Length + 1]; + Span data = stackalloc byte[value.Length + 1]; data[0] = address; - value.CopyTo(data.AsSpan(1)); + value.CopyTo(data[1..]); _i2cDevice.Write(data); } - private void Write(byte address, byte value) => _i2cDevice.Write(new byte[] { address, value }); + private void Write(byte address, byte value) => _i2cDevice.Write(stackalloc byte[] { address, value }); private byte UpdateByte(byte data, byte mask, int value) { @@ -368,14 +368,9 @@ private byte UpdateByte(byte data, byte mask, int value) private void UpdateMatrixRegister(int matrix) { - if (matrix is 0 && _matrix1Enabled) - { - Write(MATRIX_1_REGISTER, _buffer1); - } - - if (matrix is 1 && _matrix2Enabled) + if (_enabled[matrix]) { - Write(MATRIX_2_REGISTER, _buffer2); + Write(_matrix_registers[matrix], _buffers[matrix]); } WriteUpdateRegister(); From cd0dbc36af1fef2445c25db860602a9b69c444ca Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Thu, 29 Sep 2022 13:16:47 -0700 Subject: [PATCH 12/46] Add MicrDotpHat binding --- src/devices/Is31fl3730/MicroDotphat30x7.cs | 96 ++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/devices/Is31fl3730/MicroDotphat30x7.cs diff --git a/src/devices/Is31fl3730/MicroDotphat30x7.cs b/src/devices/Is31fl3730/MicroDotphat30x7.cs new file mode 100644 index 0000000000..e1558cd890 --- /dev/null +++ b/src/devices/Is31fl3730/MicroDotphat30x7.cs @@ -0,0 +1,96 @@ +// 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; +using System.Collections.Generic; +using System.Device.I2c; +using System.Threading; + +namespace Iot.Device.Display +{ + /// + /// Represents a Pimoroni Micro Dot pHat. + /// + // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf + // Product: https://shop.pimoroni.com/products/microdot-phat + // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout + // Related repo: https://github.com/pimoroni/microdot-phat + public class MicroDotpHat30x7 : IDisposable + { + private readonly Matrix3730 _matrixOne; + private readonly Matrix3730 _matrixTwo; + private readonly Matrix3730[] _pair = new Matrix3730[2]; + private Is31fl3730 _is31fl3730; + private I2cDevice? _i2cDevice; + + /// + /// Initialize IS31FL3730 device + /// + /// The to create with. + public BreakoutPair5x7(I2cDevice? i2cDevice = null) + { + _i2cDevice = i2cDevice is not null ? i2cDevice : I2cDevice.Create(new(1, Is31fl3730.DefaultI2cAddress)); + _is31fl3730 = new(_i2cDevice); + _is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; + _is31fl3730.Initialize(); + _matrixOne = new Matrix3730(_is31fl3730, 0); + _matrixTwo = new Matrix3730(_is31fl3730, 1); + _pair = new Matrix3730[] { _matrixOne, _matrixTwo }; + } + + /// + /// Initialize IS31FL3730 device + /// + /// The to create with. + public BreakoutPair5x7(Is31fl3730 is31fl3730) + { + _is31fl3730 = is31fl3730; + _matrixOne = new Matrix3730(_is31fl3730, 0); + _matrixTwo = new Matrix3730(_is31fl3730, 1); + _pair = new Matrix3730[] { _matrixOne, _matrixTwo }; + } + + /// + /// Indexer for matrix pair. + /// + public Matrix3730 this[int matrix] + { + get => _pair[matrix]; + } + + /// + /// Default I2C address for device. + /// + public const int DefaultI2cAddress = 0x61; + + /// + /// Width of LED matrix (x axis). + /// + public readonly int Width = 10; + + /// + /// Height of LED matrix (y axis). + /// + public readonly int Height = 7; + + /// + /// Identification of matrix (of 2). + /// + public readonly int Matrix = 0; + + /// + /// Fill All LEDs. + /// + public void Fill(int value) => _is31fl3730.FillAll(value); + + /// + public void Dispose() + { + _is31fl3730?.Dispose(); + _is31fl3730 = null!; + _i2cDevice?.Dispose(); + _i2cDevice = null!; + } + } +} From e920490e53c18c13319e90c7aae1916e8be1dc06 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Tue, 4 Oct 2022 20:26:48 -0700 Subject: [PATCH 13/46] Cleanup --- src/devices/Is31fl3730/BreakoutPair5x7.cs | 28 ++++++++++------------ src/devices/Is31fl3730/Current.cs | 18 +++++++------- src/devices/Is31fl3730/Is31fl3730.cs | 20 +++++++--------- src/devices/Is31fl3730/MicroDotphat30x7.cs | 6 ++--- 4 files changed, 33 insertions(+), 39 deletions(-) diff --git a/src/devices/Is31fl3730/BreakoutPair5x7.cs b/src/devices/Is31fl3730/BreakoutPair5x7.cs index ec75129e78..709fe80d19 100644 --- a/src/devices/Is31fl3730/BreakoutPair5x7.cs +++ b/src/devices/Is31fl3730/BreakoutPair5x7.cs @@ -13,16 +13,12 @@ namespace Iot.Device.Display /// Represents an IS31FL3731 LED Matrix driver /// // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf - // Product: https://shop.pimoroni.com/products/microdot-phat // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat public class BreakoutPair5x7 : IDisposable { - private readonly Matrix3730 _matrixOne; - private readonly Matrix3730 _matrixTwo; - private readonly Matrix3730[] _pair = new Matrix3730[2]; + private readonly Matrix3730[] _pair; private Is31fl3730 _is31fl3730; - private I2cDevice? _i2cDevice; /// /// Initialize IS31FL3730 device @@ -30,13 +26,15 @@ public class BreakoutPair5x7 : IDisposable /// The to create with. public BreakoutPair5x7(I2cDevice? i2cDevice = null) { - _i2cDevice = i2cDevice is not null ? i2cDevice : I2cDevice.Create(new(1, Is31fl3730.DefaultI2cAddress)); - _is31fl3730 = new(_i2cDevice); + i2cDevice = i2cDevice is not null ? i2cDevice : I2cDevice.Create(new(1, Is31fl3730.DefaultI2cAddress)); + _is31fl3730 = new(i2cDevice); _is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; _is31fl3730.Initialize(); - _matrixOne = new Matrix3730(_is31fl3730, 0); - _matrixTwo = new Matrix3730(_is31fl3730, 1); - _pair = new Matrix3730[] { _matrixOne, _matrixTwo }; + _pair = new Matrix3730[] + { + new Matrix3730(_is31fl3730, 0), + new Matrix3730(_is31fl3730, 1) + }; } /// @@ -46,9 +44,11 @@ public BreakoutPair5x7(I2cDevice? i2cDevice = null) public BreakoutPair5x7(Is31fl3730 is31fl3730) { _is31fl3730 = is31fl3730; - _matrixOne = new Matrix3730(_is31fl3730, 0); - _matrixTwo = new Matrix3730(_is31fl3730, 1); - _pair = new Matrix3730[] { _matrixOne, _matrixTwo }; + _pair = new Matrix3730[] + { + new Matrix3730(_is31fl3730, 0), + new Matrix3730(_is31fl3730, 1) + }; } /// @@ -89,8 +89,6 @@ public void Dispose() { _is31fl3730?.Dispose(); _is31fl3730 = null!; - _i2cDevice?.Dispose(); - _i2cDevice = null!; } } } diff --git a/src/devices/Is31fl3730/Current.cs b/src/devices/Is31fl3730/Current.cs index 4852a2fa22..30084ddf5a 100644 --- a/src/devices/Is31fl3730/Current.cs +++ b/src/devices/Is31fl3730/Current.cs @@ -18,31 +18,31 @@ public enum Current /// /// 5 mA /// - MA5 = 0b1000, + CmA5 = 0b1000, /// /// 10 mA /// - MA10 = 0b1001, + CmA10 = 0b1001, /// /// 35 mA /// - MA35 = 0b1110, + CmA35 = 0b1110, /// - /// 10 mA + /// 40 mA /// - MA40 = 0b0, + CmA40 = 0b0, /// - /// 10 mA + /// 45 mA /// - MA45 = 0b0001, + cMA45 = 0b0001, /// - /// 40 mA + /// 75 mA /// - MA75 = 0b0111, + CmA75 = 0b0111, } } diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index ae39e692ce..f70feee5f1 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -36,8 +36,14 @@ public class Is31fl3730 : IDisposable // Values private const byte EIGHT_BIT_VALUE = 0x80; + private const int MATRIX_ONE_DECIMAL_MASK = 128; + private const int MATRIX_TWO_DECIMAL_MASK = 64; private readonly byte[] _matrix_registers = new byte[] { MATRIX_1_REGISTER, MATRIX_2_REGISTER }; - private readonly List _buffers; + private readonly List _buffers = new List + { + new byte[8], + new byte[8] + }; private readonly bool[] _enabled = new bool[2]; private I2cDevice _i2cDevice; private int _configurationValue = 0; @@ -49,11 +55,6 @@ public class Is31fl3730 : IDisposable public Is31fl3730(I2cDevice i2cDevice) { _i2cDevice = i2cDevice; - _buffers = new List() - { - new byte[8], - new byte[8] - }; } /* @@ -74,7 +75,6 @@ public Is31fl3730(I2cDevice i2cDevice) This ordering makes sense if you are scrolling content right to left. More detailed information about the structure of each pair follows (further down). - */ /// @@ -276,13 +276,9 @@ public int ReadLed(int matrix, int x, int y) /// public void UpdateDecimalPoint(int matrix, int value) { - int matrixOneMask = 128; - int matrixtwoMask = 64; - - int mask = matrix is 0 ? matrixOneMask : matrixtwoMask; + int mask = matrix is 0 ? MATRIX_ONE_DECIMAL_MASK : MATRIX_TWO_DECIMAL_MASK; int row = matrix is 0 ? 6 : 7; byte[] buffer = _buffers[matrix]; - buffer[row] = UpdateByte(buffer[row], (byte)mask, value); } diff --git a/src/devices/Is31fl3730/MicroDotphat30x7.cs b/src/devices/Is31fl3730/MicroDotphat30x7.cs index e1558cd890..2c4e364ac3 100644 --- a/src/devices/Is31fl3730/MicroDotphat30x7.cs +++ b/src/devices/Is31fl3730/MicroDotphat30x7.cs @@ -16,7 +16,7 @@ namespace Iot.Device.Display // Product: https://shop.pimoroni.com/products/microdot-phat // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat - public class MicroDotpHat30x7 : IDisposable + public class MicroDotPhat30x7 : IDisposable { private readonly Matrix3730 _matrixOne; private readonly Matrix3730 _matrixTwo; @@ -28,7 +28,7 @@ public class MicroDotpHat30x7 : IDisposable /// Initialize IS31FL3730 device /// /// The to create with. - public BreakoutPair5x7(I2cDevice? i2cDevice = null) + public MicroDotPhat30x7(I2cDevice? i2cDevice = null) { _i2cDevice = i2cDevice is not null ? i2cDevice : I2cDevice.Create(new(1, Is31fl3730.DefaultI2cAddress)); _is31fl3730 = new(_i2cDevice); @@ -43,7 +43,7 @@ public BreakoutPair5x7(I2cDevice? i2cDevice = null) /// Initialize IS31FL3730 device /// /// The to create with. - public BreakoutPair5x7(Is31fl3730 is31fl3730) + public MicroDotPhat30x7(Is31fl3730 is31fl3730) { _is31fl3730 = is31fl3730; _matrixOne = new Matrix3730(_is31fl3730, 0); From 3e81307d3eb7799bacd60add723859dffde83835 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Tue, 29 Nov 2022 22:15:58 -0800 Subject: [PATCH 14/46] Update per feedback --- src/devices/Is31fl3730/BreakoutPair5x7.cs | 18 +++---- src/devices/Is31fl3730/Current.cs | 6 +-- src/devices/Is31fl3730/DisplayMode.cs | 4 +- src/devices/Is31fl3730/Is31fl3730.cs | 60 ++++++++-------------- src/devices/Is31fl3730/Is31fl3730.csproj | 9 +++- src/devices/Is31fl3730/MatrixMode.cs | 12 ++--- src/devices/Is31fl3730/MatrixValues.cs | 26 ++++++++++ src/devices/Is31fl3730/MicroDotphat30x7.cs | 17 ++---- src/devices/Is31fl3730/Registers.cs | 57 ++++++++++++++++++++ 9 files changed, 131 insertions(+), 78 deletions(-) create mode 100644 src/devices/Is31fl3730/MatrixValues.cs create mode 100644 src/devices/Is31fl3730/Registers.cs diff --git a/src/devices/Is31fl3730/BreakoutPair5x7.cs b/src/devices/Is31fl3730/BreakoutPair5x7.cs index 709fe80d19..14f4f7014e 100644 --- a/src/devices/Is31fl3730/BreakoutPair5x7.cs +++ b/src/devices/Is31fl3730/BreakoutPair5x7.cs @@ -15,7 +15,7 @@ namespace Iot.Device.Display // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat - public class BreakoutPair5x7 : IDisposable + public class BreakoutPair5x7 { private readonly Matrix3730[] _pair; private Is31fl3730 _is31fl3730; @@ -24,14 +24,14 @@ public class BreakoutPair5x7 : IDisposable /// Initialize IS31FL3730 device /// /// The to create with. - public BreakoutPair5x7(I2cDevice? i2cDevice = null) + public BreakoutPair5x7(I2cDevice i2cDevice) { - i2cDevice = i2cDevice is not null ? i2cDevice : I2cDevice.Create(new(1, Is31fl3730.DefaultI2cAddress)); + i2cDevice = i2cDevice ?? throw new ArgumentException($"{nameof(i2cDevice)} is null."); _is31fl3730 = new(i2cDevice); _is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; _is31fl3730.Initialize(); _pair = new Matrix3730[] - { + { new Matrix3730(_is31fl3730, 0), new Matrix3730(_is31fl3730, 1) }; @@ -43,9 +43,10 @@ public BreakoutPair5x7(I2cDevice? i2cDevice = null) /// The to create with. public BreakoutPair5x7(Is31fl3730 is31fl3730) { + is31fl3730 = is31fl3730 ?? throw new ArgumentException($"{nameof(is31fl3730)} is null."); _is31fl3730 = is31fl3730; _pair = new Matrix3730[] - { + { new Matrix3730(_is31fl3730, 0), new Matrix3730(_is31fl3730, 1) }; @@ -83,12 +84,5 @@ public BreakoutPair5x7(Is31fl3730 is31fl3730) /// Fill All LEDs. /// public void Fill(int value) => _is31fl3730.FillAll(value); - - /// - public void Dispose() - { - _is31fl3730?.Dispose(); - _is31fl3730 = null!; - } } } diff --git a/src/devices/Is31fl3730/Current.cs b/src/devices/Is31fl3730/Current.cs index 30084ddf5a..122f7da9ad 100644 --- a/src/devices/Is31fl3730/Current.cs +++ b/src/devices/Is31fl3730/Current.cs @@ -2,10 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Threading; -using System.Threading.Tasks; using System.Device.Gpio; using System.Device.Spi; +using System.Threading; +using System.Threading.Tasks; using Iot.Device.Multiplexing.Utility; namespace Iot.Device.Display @@ -38,7 +38,7 @@ public enum Current /// /// 45 mA /// - cMA45 = 0b0001, + CMA45 = 0b0001, /// /// 75 mA diff --git a/src/devices/Is31fl3730/DisplayMode.cs b/src/devices/Is31fl3730/DisplayMode.cs index 894cbfe44d..f2a1d806ab 100644 --- a/src/devices/Is31fl3730/DisplayMode.cs +++ b/src/devices/Is31fl3730/DisplayMode.cs @@ -2,10 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Threading; -using System.Threading.Tasks; using System.Device.Gpio; using System.Device.Spi; +using System.Threading; +using System.Threading.Tasks; using Iot.Device.Multiplexing.Utility; namespace Iot.Device.Display diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index f70feee5f1..fa7404b7f1 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Device.I2c; -using System.Threading; using static System.Linq.Enumerable; namespace Iot.Device.Display @@ -17,28 +16,9 @@ namespace Iot.Device.Display // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat // Based on: https://github.com/pimoroni/microdot-phat/blob/master/library/microdotphat/matrix.py - public class Is31fl3730 : IDisposable + public class Is31fl3730 { - // Function register - // table 2 in datasheet - private const byte CONFIGURATION_REGISTER = 0x0; - private const byte MATRIX_1_REGISTER = 0x1; - private const byte MATRIX_2_REGISTER = 0x0E; - private const int MATRIX_REGISTER_LENGTH = 8; - private const byte UPDATE_COLUMN_REGISTER = 0x0C; - private const byte LIGHTING_EFFECT_REGISTER = 0x0D; - private const byte PWM_REGISTER = 0x19; - private const byte RESET_REGISTER = 0x0C; - - // Configuration register - // table 3 in datasheet - private const byte SHUTDOWN = 0x80; - - // Values - private const byte EIGHT_BIT_VALUE = 0x80; - private const int MATRIX_ONE_DECIMAL_MASK = 128; - private const int MATRIX_TWO_DECIMAL_MASK = 64; - private readonly byte[] _matrix_registers = new byte[] { MATRIX_1_REGISTER, MATRIX_2_REGISTER }; + private readonly byte[] _matrix_registers = new byte[] { FunctionRegister.Matrix1, FunctionRegister.Matrix2 }; private readonly List _buffers = new List { new byte[8], @@ -54,7 +34,7 @@ public class Is31fl3730 : IDisposable /// The to create with. public Is31fl3730(I2cDevice i2cDevice) { - _i2cDevice = i2cDevice; + _i2cDevice = i2cDevice ?? throw new ArgumentException($"{nameof(i2cDevice)} is null."); } /* @@ -130,17 +110,17 @@ public void Initialize() if (_configurationValue > 0) { - Write(CONFIGURATION_REGISTER, (byte)_configurationValue); + Write(FunctionRegister.Configuration, (byte)_configurationValue); } if (Current > 0) { - Write(LIGHTING_EFFECT_REGISTER, (byte)Current); + Write(FunctionRegister.LightingEffect, (byte)Current); } if (Brightness > 0) { - Write(PWM_REGISTER, (byte)Brightness); + Write(FunctionRegister.Pwm, (byte)Brightness); } } @@ -153,6 +133,13 @@ public void Initialize() /// The value to write. public void WriteLed(int matrix, int x, int y, int value) { + if (matrix > 1 || + x > 4 || + y > 6) + { + throw new ArgumentException("Argument out of range."); + } + /* The following diagrams and information demonstrate how the matrix is structured. @@ -162,7 +149,7 @@ public void WriteLed(int matrix, int x, int y, int value) - https://shop.pimoroni.com/products/led-dot-matrix-breakout - Both of these products present pairs of 5x7 LED mattrices. + Both of these products present pairs of 5x7 LED matrices. *matrix 2* xxxxx | xxxxx @@ -276,7 +263,7 @@ public int ReadLed(int matrix, int x, int y) /// public void UpdateDecimalPoint(int matrix, int value) { - int mask = matrix is 0 ? MATRIX_ONE_DECIMAL_MASK : MATRIX_TWO_DECIMAL_MASK; + int mask = matrix is 0 ? MatrixValues.MatrixOneDecimalMask : MatrixValues.MatrixTwoDecimalMask; int row = matrix is 0 ? 6 : 7; byte[] buffer = _buffers[matrix]; buffer[row] = UpdateByte(buffer[row], (byte)mask, value); @@ -308,7 +295,7 @@ public void Fill(int matrix, int value) /// /// Reset device. /// - public void Reset() => Write(RESET_REGISTER, EIGHT_BIT_VALUE); + public void Reset() => Write(FunctionRegister.Reset, MatrixValues.EightBitValue); /// /// Set the shutdown mode. @@ -321,24 +308,17 @@ public void Shutdown(bool shutdown) // 1 = shutdown mode if (shutdown) { - _configurationValue |= SHUTDOWN; + _configurationValue |= ConfigurationRegister.Shutdown; } else { - _configurationValue &= ~SHUTDOWN; + _configurationValue &= ~ConfigurationRegister.Shutdown; } WriteUpdateRegister(); } - /// - public void Dispose() - { - _i2cDevice?.Dispose(); - _i2cDevice = null!; - } - - private void Write(byte address, byte[] value) + private void Write(byte address, ReadOnlySpan value) { Span data = stackalloc byte[value.Length + 1]; data[0] = address; @@ -372,6 +352,6 @@ private void UpdateMatrixRegister(int matrix) WriteUpdateRegister(); } - private void WriteUpdateRegister() => Write(UPDATE_COLUMN_REGISTER, EIGHT_BIT_VALUE); + private void WriteUpdateRegister() => Write(FunctionRegister.UpdateColumn, MatrixValues.EightBitValue); } } diff --git a/src/devices/Is31fl3730/Is31fl3730.csproj b/src/devices/Is31fl3730/Is31fl3730.csproj index 32ca830ee1..7e89faae11 100644 --- a/src/devices/Is31fl3730/Is31fl3730.csproj +++ b/src/devices/Is31fl3730/Is31fl3730.csproj @@ -4,11 +4,16 @@ false - + - + + + + + + \ No newline at end of file diff --git a/src/devices/Is31fl3730/MatrixMode.cs b/src/devices/Is31fl3730/MatrixMode.cs index 9385571bd7..f857cde2cd 100644 --- a/src/devices/Is31fl3730/MatrixMode.cs +++ b/src/devices/Is31fl3730/MatrixMode.cs @@ -2,10 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Threading; -using System.Threading.Tasks; using System.Device.Gpio; using System.Device.Spi; +using System.Threading; +using System.Threading.Tasks; using Iot.Device.Multiplexing.Utility; namespace Iot.Device.Display @@ -18,21 +18,21 @@ public enum MatrixMode /// /// Represents a 8x8 LED matrix. /// - Size8x8, + Size8x8 = 0, /// /// Represents a 7x9 LED matrix. /// - Size7x9, + Size7x9 = 1, /// /// Represents a 6x10 LED matrix. /// - Size6x10, + Size6x10 = 2, /// /// Represents an 5x11 LED matrix. /// - Size5x11 + Size5x11 = 3 } } diff --git a/src/devices/Is31fl3730/MatrixValues.cs b/src/devices/Is31fl3730/MatrixValues.cs new file mode 100644 index 0000000000..96f70b2fd7 --- /dev/null +++ b/src/devices/Is31fl3730/MatrixValues.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Iot.Device.Display +{ + /// + /// Matrix Values. + /// + public static class MatrixValues + { + /// + /// Address for Configuration Register. + /// + public static byte EightBitValue = 8; + + /// + /// Address for Configuration Register. + /// + public static byte MatrixOneDecimalMask = 128; + + /// + /// Address for Configuration Register. + /// + public static byte MatrixTwoDecimalMask = 64; + } +} diff --git a/src/devices/Is31fl3730/MicroDotphat30x7.cs b/src/devices/Is31fl3730/MicroDotphat30x7.cs index 2c4e364ac3..5e1b6ef84e 100644 --- a/src/devices/Is31fl3730/MicroDotphat30x7.cs +++ b/src/devices/Is31fl3730/MicroDotphat30x7.cs @@ -16,7 +16,7 @@ namespace Iot.Device.Display // Product: https://shop.pimoroni.com/products/microdot-phat // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat - public class MicroDotPhat30x7 : IDisposable + public class MicroDotPhat30x7 { private readonly Matrix3730 _matrixOne; private readonly Matrix3730 _matrixTwo; @@ -28,9 +28,9 @@ public class MicroDotPhat30x7 : IDisposable /// Initialize IS31FL3730 device /// /// The to create with. - public MicroDotPhat30x7(I2cDevice? i2cDevice = null) + public MicroDotPhat30x7(I2cDevice i2cDevice) { - _i2cDevice = i2cDevice is not null ? i2cDevice : I2cDevice.Create(new(1, Is31fl3730.DefaultI2cAddress)); + i2cDevice = i2cDevice ?? throw new ArgumentException($"{nameof(i2cDevice)} is null."); _is31fl3730 = new(_i2cDevice); _is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; _is31fl3730.Initialize(); @@ -45,7 +45,7 @@ public MicroDotPhat30x7(I2cDevice? i2cDevice = null) /// The to create with. public MicroDotPhat30x7(Is31fl3730 is31fl3730) { - _is31fl3730 = is31fl3730; + is31fl3730 = is31fl3730 ?? throw new ArgumentException($"{nameof(is31fl3730)} is null."); _matrixOne = new Matrix3730(_is31fl3730, 0); _matrixTwo = new Matrix3730(_is31fl3730, 1); _pair = new Matrix3730[] { _matrixOne, _matrixTwo }; @@ -83,14 +83,5 @@ public MicroDotPhat30x7(Is31fl3730 is31fl3730) /// Fill All LEDs. /// public void Fill(int value) => _is31fl3730.FillAll(value); - - /// - public void Dispose() - { - _is31fl3730?.Dispose(); - _is31fl3730 = null!; - _i2cDevice?.Dispose(); - _i2cDevice = null!; - } } } diff --git a/src/devices/Is31fl3730/Registers.cs b/src/devices/Is31fl3730/Registers.cs new file mode 100644 index 0000000000..ee61563547 --- /dev/null +++ b/src/devices/Is31fl3730/Registers.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Iot.Device.Display +{ + /// + /// Register addresses for the Function Register. + /// + public static class FunctionRegister + { + /// + /// Address for Configuration Register. + /// + public static byte Configuration = 0x0; + + /// + /// Address for Matrix 1 Data Register. + /// + public static byte Matrix1 = 0x1; + + /// + /// Address for Matrix 2 Data Register. + /// + public static byte Matrix2 = 0x0E; + + /// + /// Address for Update Column Register. + /// + public static byte UpdateColumn = 0x0C; + + /// + /// Address for Lighting Effect Register. + /// + public static byte LightingEffect = 0x0D; + + /// + /// Address for PWM Register. + /// + public static byte Pwm = 0x19; + + /// + /// Address for Reset Register. + /// + public static byte Reset = 0x0C; + } + + /// + /// Register addresses for the Configuration Register. + /// + public static class ConfigurationRegister + { + /// + /// Shutdown value. + /// + public static byte Shutdown = 0x80; + } +} From d82f7ff6fe4e67c4401537151595da18840315a6 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 30 Nov 2022 07:17:06 -0800 Subject: [PATCH 15/46] Add Index/Range support for netstandard2.0 --- src/devices/Common/Common.csproj | 2 + src/devices/Common/IndexRange.cs | 252 +++++++++++++++++++++++++++ src/devices/Common/RuntimeHelpers.cs | 43 +++++ 3 files changed, 297 insertions(+) create mode 100644 src/devices/Common/IndexRange.cs create mode 100644 src/devices/Common/RuntimeHelpers.cs diff --git a/src/devices/Common/Common.csproj b/src/devices/Common/Common.csproj index 10d8bb1fea..d937babd8d 100644 --- a/src/devices/Common/Common.csproj +++ b/src/devices/Common/Common.csproj @@ -24,6 +24,8 @@ + + diff --git a/src/devices/Common/IndexRange.cs b/src/devices/Common/IndexRange.cs new file mode 100644 index 0000000000..28f076d60f --- /dev/null +++ b/src/devices/Common/IndexRange.cs @@ -0,0 +1,252 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +// From: +// https://github.com/dotnet/runtime/blob/419e949d258ecee4c40a460fb09c66d974229623/src/libraries/System.Private.CoreLib/src/System/Index.cs +// https://github.com/dotnet/runtime/blob/419e949d258ecee4c40a460fb09c66d974229623/src/libraries/System.Private.CoreLib/src/System/Range.cs +// https://www.meziantou.net/assets/range.zip +namespace System +{ + /// Represent a type can be used to index a collection either from the start or the end. + /// + /// Index is used by the C# compiler to support the new index syntax + /// + /// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ; + /// int lastElement = someArray[^1]; // lastElement = 5 + /// + /// + public readonly struct Index : IEquatable + { + private readonly int _value; + + /// Construct an Index using a value and indicating if the index is from the start or from the end. + /// The index value. it has to be zero or positive number. + /// Indicating if the index is from the start or from the end. + /// + /// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Index(int value, bool fromEnd = false) + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative"); + } + + if (fromEnd) + { + _value = ~value; + } + else + { + _value = value; + } + } + + // The following private constructors mainly created for perf reason to avoid the checks + private Index(int value) + { + _value = value; + } + + /// Create an Index pointing at first element. + public static Index Start => new Index(0); + + /// Create an Index pointing at beyond last element. + public static Index End => new Index(~0); + + /// Create an Index from the start at the position indicated by the value. + /// The index value from the start. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Index FromStart(int value) + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative"); + } + + return new Index(value); + } + + /// Create an Index from the end at the position indicated by the value. + /// The index value from the end. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Index FromEnd(int value) + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative"); + } + + return new Index(~value); + } + + /// Returns the index value. + public int Value + { + get + { + if (_value < 0) + { + return ~_value; + } + else + { + return _value; + } + } + } + + /// Indicates whether the index is from the start or the end. + public bool IsFromEnd => _value < 0; + + /// Calculate the offset from the start using the giving collection length. + /// The length of the collection that the Index will be used with. length has to be a positive value + /// + /// For performance reason, we don't validate the input length parameter and the returned offset value against negative values. + /// we don't validate either the returned offset is greater than the input length. + /// It is expected Index will be used with collections which always have non negative length/count. If the returned offset is negative and + /// then used to index a collection will get out of range exception which will be same affect as the validation. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int GetOffset(int length) + { + var offset = _value; + if (IsFromEnd) + { + // offset = length - (~value) + // offset = length + (~(~value) + 1) + // offset = length + value + 1 + offset += length + 1; + } + + return offset; + } + + /// Indicates whether the current Index object is equal to another object of the same type. + /// An object to compare with this object + public override bool Equals(object? value) => value is Index && _value == ((Index)value)._value; + + /// Indicates whether the current Index object is equal to another Index object. + /// An object to compare with this object + public bool Equals(Index other) => _value == other._value; + + /// Returns the hash code for this instance. + public override int GetHashCode() => _value; + + /// Converts integer number to an Index. + public static implicit operator Index(int value) => FromStart(value); + + /// Converts the value of the current Index object to its equivalent string representation. + public override string ToString() + { + if (IsFromEnd) + { + return "^" + ((uint)Value).ToString(); + } + + return ((uint)Value).ToString(); + } + } + + /// Represent a range has start and end indexes. + /// + /// Range is used by the C# compiler to support the range syntax. + /// + /// int[] someArray = new int[5] { 1, 2, 3, 4, 5 }; + /// int[] subArray1 = someArray[0..2]; // { 1, 2 } + /// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 } + /// + /// + public readonly struct Range : IEquatable + { + /// Create a Range object starting from start index to the end of the collection. + public static Range StartAt(Index start) => new Range(start, Index.End); + + /// Create a Range object starting from first element in the collection to the end Index. + public static Range EndAt(Index end) => new Range(Index.Start, end); + + /// Create a Range object starting from first element to the end. + public static Range All => new Range(Index.Start, Index.End); + + /// Represent the inclusive start index of the Range. + public Index Start { get; } + + /// Represent the exclusive end index of the Range. + public Index End { get; } + + /// Construct a Range object using the start and end indexes. + /// Represent the inclusive start index of the range. + /// Represent the exclusive end index of the range. + public Range(Index start, Index end) + { + Start = start; + End = end; + } + + /// Indicates whether the current Range object is equal to another object of the same type. + /// An object to compare with this object + public override bool Equals(object? value) => + value is Range r && + r.Start.Equals(Start) && + r.End.Equals(End); + + /// Indicates whether the current Range object is equal to another Range object. + /// An object to compare with this object + public bool Equals(Range other) => other.Start.Equals(Start) && other.End.Equals(End); + + /// Returns the hash code for this instance. + public override int GetHashCode() + { + return Start.GetHashCode() * 31 + End.GetHashCode(); + } + + /// Converts the value of the current Range object to its equivalent string representation. + public override string ToString() + { + return Start + ".." + End; + } + + /// Calculate the start offset and length of range object using a collection length. + /// The length of the collection that the range will be used with. length has to be a positive value. + /// + /// For performance reason, we don't validate the input length parameter against negative values. + /// It is expected Range will be used with collections which always have non negative length/count. + /// We validate the range is inside the length scope though. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public (int Offset, int Length) GetOffsetAndLength(int length) + { + int start; + var startIndex = Start; + if (startIndex.IsFromEnd) + { + start = length - startIndex.Value; + } + else + { + start = startIndex.Value; + } + + int end; + var endIndex = End; + if (endIndex.IsFromEnd) + { + end = length - endIndex.Value; + } + else + { + end = endIndex.Value; + } + + if ((uint)end > (uint)length || (uint)start > (uint)end) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + return (start, end - start); + } + } +} diff --git a/src/devices/Common/RuntimeHelpers.cs b/src/devices/Common/RuntimeHelpers.cs new file mode 100644 index 0000000000..9d3d611437 --- /dev/null +++ b/src/devices/Common/RuntimeHelpers.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.CompilerServices +{ + // From: + // https://www.meziantou.net/assets/range.zip + internal static class RuntimeHelpers + { + /// + /// Slices the specified array using the specified range. + /// + public static T[] GetSubArray(T[] array, Range range) + { + if (array == null) + { + throw new ArgumentNullException(nameof(array)); + } + + (int offset, int length) = range.GetOffsetAndLength(array.Length); + + if (default(T) != null || typeof(T[]) == array.GetType()) + { + // We know the type of the array to be exactly T[]. + if (length == 0) + { + return Array.Empty(); + } + + var dest = new T[length]; + Array.Copy(array, offset, dest, 0, length); + return dest; + } + else + { + // The array is actually a U[] where U:T. + var dest = (T[])Array.CreateInstance(array.GetType().GetElementType(), length); + Array.Copy(array, offset, dest, 0, length); + return dest; + } + } + } +} From 8f7d96167d64301afb003be4a385d01b756d78df Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Tue, 13 Dec 2022 19:56:13 -0800 Subject: [PATCH 16/46] Enable decimal point --- src/devices/Is31fl3730/Is31fl3730.cs | 7 ++++--- src/devices/Is31fl3730/samples/Program.cs | 9 +++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index fa7404b7f1..c370fc5831 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -263,10 +263,11 @@ public int ReadLed(int matrix, int x, int y) /// public void UpdateDecimalPoint(int matrix, int value) { - int mask = matrix is 0 ? MatrixValues.MatrixOneDecimalMask : MatrixValues.MatrixTwoDecimalMask; - int row = matrix is 0 ? 6 : 7; byte[] buffer = _buffers[matrix]; - buffer[row] = UpdateByte(buffer[row], (byte)mask, value); + int row = matrix is 0 ? 6 : 7; + byte mask = matrix is 0 ? MatrixValues.MatrixOneDecimalMask : MatrixValues.MatrixTwoDecimalMask; + buffer[row] = UpdateByte(buffer[row], mask, value); + UpdateMatrixRegister(matrix); } /// diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index ab00fdb6ee..8363020369 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -8,7 +8,8 @@ using System.Threading; using Iot.Device.Display; -using BreakoutPair5x7 breakout = new(); +using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, BreakoutPair5x7.DefaultI2cAddress)); +BreakoutPair5x7 breakout = new(i2cDevice); breakout.Fill(0); Thread.Sleep(100); @@ -20,7 +21,7 @@ return; } -var matrix = mOne; +var matrix = mTwo; // Dimensions int width = matrix.Width - 1; @@ -163,3 +164,7 @@ void WriteColumnPixels(int column, IEnumerable pixels, int value) Thread.Sleep(1000); matrix.Fill(0); + +matrix.UpdateDecimalPoint(1); +Thread.Sleep(1000); +matrix.Fill(0); From 5b8c34194ac94e4323f7b9f86fb9e8f6f12e37f2 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 14 Dec 2022 14:44:13 -0800 Subject: [PATCH 17/46] Update target matrix --- src/devices/Is31fl3730/samples/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 8363020369..483a7e074f 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -21,7 +21,7 @@ return; } -var matrix = mTwo; +var matrix = mOne; // Dimensions int width = matrix.Width - 1; From 0d1e95fbea3852ca4b49b1ab99f131dc7d2c8b18 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Fri, 16 Dec 2022 21:43:42 -0800 Subject: [PATCH 18/46] Add support for Micro Dot pHat --- src/devices/Is31fl3730/Bonnet5x7x6.cs | 61 --------- .../{Matrix3730.cs => DotMatrix5x7.cs} | 24 ++-- ...outPair5x7.cs => DotMatrixBreakout10x7.cs} | 66 ++++++---- src/devices/Is31fl3730/Is31fl3730.cs | 99 +++++++++----- src/devices/Is31fl3730/Is31fl3730.csproj | 5 +- src/devices/Is31fl3730/MatrixValues.cs | 22 +++- src/devices/Is31fl3730/MicroDotPhat30x7.cs | 123 ++++++++++++++++++ src/devices/Is31fl3730/MicroDotphat30x7.cs | 87 ------------- src/devices/Is31fl3730/Registers.cs | 24 ++-- src/devices/Is31fl3730/samples/Program.cs | 31 +++-- 10 files changed, 290 insertions(+), 252 deletions(-) delete mode 100644 src/devices/Is31fl3730/Bonnet5x7x6.cs rename src/devices/Is31fl3730/{Matrix3730.cs => DotMatrix5x7.cs} (67%) rename src/devices/Is31fl3730/{BreakoutPair5x7.cs => DotMatrixBreakout10x7.cs} (58%) create mode 100644 src/devices/Is31fl3730/MicroDotPhat30x7.cs delete mode 100644 src/devices/Is31fl3730/MicroDotphat30x7.cs diff --git a/src/devices/Is31fl3730/Bonnet5x7x6.cs b/src/devices/Is31fl3730/Bonnet5x7x6.cs deleted file mode 100644 index fb93e6dc47..0000000000 --- a/src/devices/Is31fl3730/Bonnet5x7x6.cs +++ /dev/null @@ -1,61 +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.I2c; -using System.Threading; - -namespace Iot.Device.Display -{ - /// - /// Represents LED Dot Matrix Breakout - /// - // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf - // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout - // Related repo: https://github.com/pimoroni/microdot-phat - public class Matrix5x7 : IDisposable - { - private readonly Is31fl3730 _is31fl3730; - - /// - /// Initialize IS31FL3730 device - /// - /// The to create with. - /// The width of the LED matrix. - /// The height of the LED matrix. - public Matrix5x7(Is31fl3730 is31fl3730, int width, int height, int matrix) - { - _is31fl3730 = is31fl3730; - Width = width; - Height = height; - Matrix = matrix; - } - - /// - /// Indexer for matrix. - /// - public int this[int x, int y] - { - get => _is31fl3730.ReadLed(Matrix, x, y); - set => _is31fl3730.WriteLed(Matrix, x, y, value); - } - - public const int DefaultI2cAddress = 0x61; - - /// - /// Width of LED matrix (x axis). - /// - public readonly int Width = 5; - - /// - /// Height of LED matrix (y axis). - /// - public readonly int Height = 7; - - /// - /// Identification of matrix (of 2). - /// - public readonly int Matrix = 0; - } -} diff --git a/src/devices/Is31fl3730/Matrix3730.cs b/src/devices/Is31fl3730/DotMatrix5x7.cs similarity index 67% rename from src/devices/Is31fl3730/Matrix3730.cs rename to src/devices/Is31fl3730/DotMatrix5x7.cs index d527c05c70..7f810f33f8 100644 --- a/src/devices/Is31fl3730/Matrix3730.cs +++ b/src/devices/Is31fl3730/DotMatrix5x7.cs @@ -11,28 +11,29 @@ namespace Iot.Device.Display /// /// Represents LED Dot Matrix driven by IS31FL3730. /// - public class Matrix3730 + public class DotMatrix5x7 { private readonly Is31fl3730 _is31fl3730; + private readonly int _matrix; /// - /// Initialize IS31FL3730 device + /// Initialize Dot Matrix IS31FL3730 device. /// /// The to create with. /// The index of the matrix (of a pair). - public Matrix3730(Is31fl3730 is31fl3730, int matrix) + public DotMatrix5x7(Is31fl3730 is31fl3730, int matrix) { _is31fl3730 = is31fl3730; - Matrix = matrix; + _matrix = matrix; } /// - /// Indexer for matrix. + /// Indexer for matrix. x: 0..4; y: 0..6. /// public int this[int x, int y] { - get => _is31fl3730.ReadLed(Matrix, x, y); - set => _is31fl3730.WriteLed(Matrix, x, y, value); + get => _is31fl3730.Read(_matrix, x, y); + set => _is31fl3730.Write(_matrix, x, y, value); } /// @@ -45,19 +46,14 @@ public Matrix3730(Is31fl3730 is31fl3730, int matrix) /// public readonly int Height = 7; - /// - /// Identification of matrix (of 2). - /// - public readonly int Matrix = 0; - /// /// Fill matrix (0 is dark; 1 is lit). /// - public void Fill(int value) => _is31fl3730.Fill(Matrix, value); + public void Fill(int value) => _is31fl3730.Fill(_matrix, value); /// /// Fill matrix (0 is dark; 1 is lit). /// - public void UpdateDecimalPoint(int value) => _is31fl3730.UpdateDecimalPoint(Matrix, value); + public void WriteDecimalPoint(int value) => _is31fl3730.WriteDecimalPoint(_matrix, value); } } diff --git a/src/devices/Is31fl3730/BreakoutPair5x7.cs b/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs similarity index 58% rename from src/devices/Is31fl3730/BreakoutPair5x7.cs rename to src/devices/Is31fl3730/DotMatrixBreakout10x7.cs index 14f4f7014e..7ea85e0432 100644 --- a/src/devices/Is31fl3730/BreakoutPair5x7.cs +++ b/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs @@ -15,51 +15,43 @@ namespace Iot.Device.Display // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat - public class BreakoutPair5x7 + public class DotMatrixBreakout10x7 { - private readonly Matrix3730[] _pair; + private readonly DotMatrix5x7[] _matrices; private Is31fl3730 _is31fl3730; /// - /// Initialize IS31FL3730 device + /// Initialize Dot Matrix Breakout IS31FL3730 device. /// /// The to create with. - public BreakoutPair5x7(I2cDevice i2cDevice) + public DotMatrixBreakout10x7(I2cDevice i2cDevice) { i2cDevice = i2cDevice ?? throw new ArgumentException($"{nameof(i2cDevice)} is null."); _is31fl3730 = new(i2cDevice); _is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; _is31fl3730.Initialize(); - _pair = new Matrix3730[] + _matrices = new DotMatrix5x7[] { - new Matrix3730(_is31fl3730, 0), - new Matrix3730(_is31fl3730, 1) + new DotMatrix5x7(_is31fl3730, 0), + new DotMatrix5x7(_is31fl3730, 1) }; } /// - /// Initialize IS31FL3730 device + /// Initialize Dot Matrix Breakout IS31FL3730 device. /// /// The to create with. - public BreakoutPair5x7(Is31fl3730 is31fl3730) + public DotMatrixBreakout10x7(Is31fl3730 is31fl3730) { is31fl3730 = is31fl3730 ?? throw new ArgumentException($"{nameof(is31fl3730)} is null."); _is31fl3730 = is31fl3730; - _pair = new Matrix3730[] + _matrices = new DotMatrix5x7[] { - new Matrix3730(_is31fl3730, 0), - new Matrix3730(_is31fl3730, 1) + new DotMatrix5x7(_is31fl3730, 0), + new DotMatrix5x7(_is31fl3730, 1) }; } - /// - /// Indexer for matrix pair. - /// - public Matrix3730 this[int matrix] - { - get => _pair[matrix]; - } - /// /// Default I2C address for device. /// @@ -76,13 +68,41 @@ public BreakoutPair5x7(Is31fl3730 is31fl3730) public readonly int Height = 7; /// - /// Identification of matrix (of 2). + /// Indexer for matrices. /// - public readonly int Matrix = 0; + public DotMatrix5x7 this[int matrix] => _matrices[matrix]; + + /// + /// Indexer for matrix pair. + /// + public int this[int x, int y] + { + get => x switch + { + < 5 => this[0][x, y], + < 10 => this[1][x - 5, y], + _ => throw new ArgumentException($"{nameof(x)} value out of range") + }; + set + { + if (x < 5) + { + this[0][x, y] = value; + } + else if (x < 10) + { + this[1][x - 5, y] = value; + } + else + { + throw new ArgumentException($"{nameof(x)} value out of range"); + } + } + } /// /// Fill All LEDs. /// - public void Fill(int value) => _is31fl3730.FillAll(value); + public void Fill(int value) => _is31fl3730.Fill(value); } } diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index c370fc5831..9ea5def10b 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -18,7 +18,7 @@ namespace Iot.Device.Display // Based on: https://github.com/pimoroni/microdot-phat/blob/master/library/microdotphat/matrix.py public class Is31fl3730 { - private readonly byte[] _matrix_registers = new byte[] { FunctionRegister.Matrix1, FunctionRegister.Matrix2 }; + private readonly byte[] _matrix_addresses = new byte[] { FunctionRegister.Matrix1, FunctionRegister.Matrix2 }; private readonly List _buffers = new List { new byte[8], @@ -68,24 +68,29 @@ public Is31fl3730(I2cDevice i2cDevice) public static readonly int[] SupportedI2cAddresses = new int[] { DefaultI2cAddress, 0x62, 0x63 }; /// - /// Brightness of LED matrix (override default value (128; max brightness)); set before calling Initialize method). + /// Brightness of LED matrix (override default value (128; max brightness); set before calling Initialize method). /// - public int Brightness = 0; + public int Brightness { get; set; } /// /// Full current setting for each row output of LED matrix (override default value (40 mA)); set before calling Initialize method). /// - public Current Current = 0; + public Current Current { get; set; } /// /// Matrix mode (override default value (8x8); set before calling Initialize method). /// - public MatrixMode MatrixMode = 0; + public MatrixMode MatrixMode { get; set; } /// - /// Display mode (override default value (Matrix 1 only); set before calling Initialize method). + /// Display mode (use to override default value (Matrix 1 only; right-most); set before calling Initialize method). /// - public DisplayMode DisplayMode = 0; + public DisplayMode DisplayMode { get; set; } + + /// + /// Enables or disables auto-buggering. + /// + public bool BufferingEnabled { get; set; } = true; /// /// Initialize LED driver. @@ -131,15 +136,8 @@ public void Initialize() /// The x dimension for the LED. /// The y dimension for the LED. /// The value to write. - public void WriteLed(int matrix, int x, int y, int value) + public void Write(int matrix, int x, int y, int value) { - if (matrix > 1 || - x > 4 || - y > 6) - { - throw new ArgumentException("Argument out of range."); - } - /* The following diagrams and information demonstrate how the matrix is structured. @@ -233,13 +231,20 @@ x x concern. It has nothing to do with byte structure. */ + if (matrix > 1 || + x > 4 || + y > 6) + { + throw new ArgumentException("Argument out of range."); + } + int logicalRow = matrix is 0 ? y : x; int logicalColumn = matrix is 0 ? x : y; byte mask = (byte)(1 << logicalColumn); byte[] buffer = _buffers[matrix]; buffer[logicalRow] = UpdateByte(buffer[logicalRow], mask, value); - UpdateMatrixRegister(matrix); + AutoFlush(matrix); } /// @@ -248,7 +253,7 @@ x x /// The matrix to use. /// The x dimension for the LED. /// The y dimension for the LED. - public int ReadLed(int matrix, int x, int y) + public int Read(int matrix, int x, int y) { int row = matrix is 0 ? y : x; int column = matrix is 0 ? x : y; @@ -261,19 +266,28 @@ public int ReadLed(int matrix, int x, int y) /// /// Update decimal point for matrix. /// - public void UpdateDecimalPoint(int matrix, int value) + public void WriteDecimalPoint(int matrix, int value) { byte[] buffer = _buffers[matrix]; - int row = matrix is 0 ? 6 : 7; + int row = matrix is 0 ? MatrixValues.MatrixOneDecimalRow : MatrixValues.MatrixTwoDecimalRow; byte mask = matrix is 0 ? MatrixValues.MatrixOneDecimalMask : MatrixValues.MatrixTwoDecimalMask; buffer[row] = UpdateByte(buffer[row], mask, value); - UpdateMatrixRegister(matrix); + AutoFlush(matrix); } /// - /// Fill all LEDs with value. + /// Fill LEDs with value, per matrix. /// - public void FillAll(int value) + public void Fill(int matrix, int value) + { + _buffers[matrix].AsSpan().Fill((byte)value); + AutoFlush(matrix); + } + + /// + /// Fill LEDs with value. + /// + public void Fill(int value) { foreach (int i in Range(0, 2)) { @@ -285,16 +299,28 @@ public void FillAll(int value) } /// - /// Fill all LEDs with value, per Matrix. + /// Fill LEDs with value, per matrix. /// - public void Fill(int matrix, int value) + public void Flush(int matrix) { - _buffers[matrix].AsSpan().Fill((byte)value); - UpdateMatrixRegister(matrix); + if (_enabled[matrix]) + { + Write(_matrix_addresses[matrix], _buffers[matrix]); + WriteUpdateRegister(); + } + } + + /// + /// Fill LEDs with value. + /// + public void Flush() + { + Flush(0); + Flush(1); } /// - /// Reset device. + /// Resets all registers to default value. /// public void Reset() => Write(FunctionRegister.Reset, MatrixValues.EightBitValue); @@ -343,16 +369,21 @@ private byte UpdateByte(byte data, byte mask, int value) return data; } - private void UpdateMatrixRegister(int matrix) + /* + Per the datasheet: + The data sent to the Data Registers will be stored in + temporary registers. A write operation of any 8-bit value + to the Update Column Register is required to update + the Data Registers (01h~0Bh, 0Eh~18h). + */ + private void WriteUpdateRegister() => Write(FunctionRegister.UpdateColumn, MatrixValues.EightBitValue); + + private void AutoFlush(int matrix) { - if (_enabled[matrix]) + if (BufferingEnabled) { - Write(_matrix_registers[matrix], _buffers[matrix]); + Flush(matrix); } - - WriteUpdateRegister(); } - - private void WriteUpdateRegister() => Write(FunctionRegister.UpdateColumn, MatrixValues.EightBitValue); } } diff --git a/src/devices/Is31fl3730/Is31fl3730.csproj b/src/devices/Is31fl3730/Is31fl3730.csproj index 7e89faae11..9151f68d22 100644 --- a/src/devices/Is31fl3730/Is31fl3730.csproj +++ b/src/devices/Is31fl3730/Is31fl3730.csproj @@ -13,7 +13,8 @@ - - + + + \ No newline at end of file diff --git a/src/devices/Is31fl3730/MatrixValues.cs b/src/devices/Is31fl3730/MatrixValues.cs index 96f70b2fd7..b5c8b10366 100644 --- a/src/devices/Is31fl3730/MatrixValues.cs +++ b/src/devices/Is31fl3730/MatrixValues.cs @@ -9,18 +9,34 @@ namespace Iot.Device.Display public static class MatrixValues { /// - /// Address for Configuration Register. + /// Arbitrary 8-bit value to write to Update Column Register, as required by datasheet. /// public static byte EightBitValue = 8; /// - /// Address for Configuration Register. + /// Matrix one decimal point mask. /// public static byte MatrixOneDecimalMask = 128; /// - /// Address for Configuration Register. + /// Matrix one decimal point row. + /// + public static byte MatrixOneDecimalRow = 6; + + /// + /// Matrix two mask for decimal point. /// public static byte MatrixTwoDecimalMask = 64; + + /// + /// Matrix two decimal point row. + /// + public static byte MatrixTwoDecimalRow = 7; + + /// + /// I2C addresses for Micro Dot pHat, right to left. + /// + public static int[] Addresses = new int[] { 0x63, 0x62, 0x61 }; + } } diff --git a/src/devices/Is31fl3730/MicroDotPhat30x7.cs b/src/devices/Is31fl3730/MicroDotPhat30x7.cs new file mode 100644 index 0000000000..ff56ff77d6 --- /dev/null +++ b/src/devices/Is31fl3730/MicroDotPhat30x7.cs @@ -0,0 +1,123 @@ +// 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; +using System.Collections.Generic; +using System.Device.I2c; +using System.Linq; +using System.Threading; + +namespace Iot.Device.Display +{ + /// + /// Represents a Pimoroni Micro Dot pHat. + /// + // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf + // Product: https://shop.pimoroni.com/products/microdot-phat + // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout + // Related repo: https://github.com/pimoroni/microdot-phat + public class MicroDotPhat30x7 + { + private DotMatrixBreakout10x7[] _pairs; + private DotMatrix5x7[] _matrices = new DotMatrix5x7[6]; + + /// + /// Initialize Micro Dot pHAT IS31FL3730 device. + /// + public MicroDotPhat30x7() + { + _pairs = new DotMatrixBreakout10x7[3]; + + foreach (var pair in Enumerable.Range(0, 3)) + { + I2cDevice i2cDevice = I2cDevice.Create(new(1, MatrixValues.Addresses[pair])); + _pairs[pair] = new DotMatrixBreakout10x7(i2cDevice); + _matrices[pair * 2] = _pairs[pair][1]; + _matrices[pair * 2 + 1] = _pairs[pair][0]; + } + } + + /// + /// Initialize Micro Dot pHAT IS31FL3730 device. + /// + /// The first Dot Matrix pair. + /// The first Dot Matrix pair. + /// The first Dot Matrix pair. + public MicroDotPhat30x7(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) + { + if (first is null || second is null || third is null) + { + throw new ArgumentException($"Input argument is null."); + } + + _pairs = new DotMatrixBreakout10x7[] + { + new(first), + new(second), + new(third) + }; + + foreach (var pair in Enumerable.Range(0, 3)) + { + _matrices[pair * 2] = _pairs[pair][1]; + _matrices[pair * 2 + 1] = _pairs[pair][0]; + } + } + + /// + /// Width of LED matrix (x axis). + /// + public readonly int Width = 30; + + /// + /// Height of LED matrix (y axis). + /// + public readonly int Height = 7; + + /// + /// Indexer for matrices. + /// + public DotMatrix5x7 this[int matrix] => _matrices[matrix]; + + /// + /// Indexer for Micro Dot pHat matrix. + /// + public int this[int x, int y] + { + get + { + if (x >= 30 || y > 6) + { + throw new ArgumentException("Input value out of range."); + } + + int matrix = x % 5; + int modx = x - (matrix * 5); + return this[matrix][modx, y]; + } + set + { + if (x >= 30 || y > 6) + { + throw new ArgumentException("Input value out of range."); + } + + int matrix = x / 5; + int modx = x - (matrix * 5); + this[matrix][modx, y] = value; + } + } + + /// + /// Fill All LEDs. + /// + public void Fill(int value) + { + foreach (var pair in _pairs) + { + pair.Fill(value); + } + } + } +} diff --git a/src/devices/Is31fl3730/MicroDotphat30x7.cs b/src/devices/Is31fl3730/MicroDotphat30x7.cs deleted file mode 100644 index 5e1b6ef84e..0000000000 --- a/src/devices/Is31fl3730/MicroDotphat30x7.cs +++ /dev/null @@ -1,87 +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; -using System.Collections.Generic; -using System.Device.I2c; -using System.Threading; - -namespace Iot.Device.Display -{ - /// - /// Represents a Pimoroni Micro Dot pHat. - /// - // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf - // Product: https://shop.pimoroni.com/products/microdot-phat - // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout - // Related repo: https://github.com/pimoroni/microdot-phat - public class MicroDotPhat30x7 - { - private readonly Matrix3730 _matrixOne; - private readonly Matrix3730 _matrixTwo; - private readonly Matrix3730[] _pair = new Matrix3730[2]; - private Is31fl3730 _is31fl3730; - private I2cDevice? _i2cDevice; - - /// - /// Initialize IS31FL3730 device - /// - /// The to create with. - public MicroDotPhat30x7(I2cDevice i2cDevice) - { - i2cDevice = i2cDevice ?? throw new ArgumentException($"{nameof(i2cDevice)} is null."); - _is31fl3730 = new(_i2cDevice); - _is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; - _is31fl3730.Initialize(); - _matrixOne = new Matrix3730(_is31fl3730, 0); - _matrixTwo = new Matrix3730(_is31fl3730, 1); - _pair = new Matrix3730[] { _matrixOne, _matrixTwo }; - } - - /// - /// Initialize IS31FL3730 device - /// - /// The to create with. - public MicroDotPhat30x7(Is31fl3730 is31fl3730) - { - is31fl3730 = is31fl3730 ?? throw new ArgumentException($"{nameof(is31fl3730)} is null."); - _matrixOne = new Matrix3730(_is31fl3730, 0); - _matrixTwo = new Matrix3730(_is31fl3730, 1); - _pair = new Matrix3730[] { _matrixOne, _matrixTwo }; - } - - /// - /// Indexer for matrix pair. - /// - public Matrix3730 this[int matrix] - { - get => _pair[matrix]; - } - - /// - /// Default I2C address for device. - /// - public const int DefaultI2cAddress = 0x61; - - /// - /// Width of LED matrix (x axis). - /// - public readonly int Width = 10; - - /// - /// Height of LED matrix (y axis). - /// - public readonly int Height = 7; - - /// - /// Identification of matrix (of 2). - /// - public readonly int Matrix = 0; - - /// - /// Fill All LEDs. - /// - public void Fill(int value) => _is31fl3730.FillAll(value); - } -} diff --git a/src/devices/Is31fl3730/Registers.cs b/src/devices/Is31fl3730/Registers.cs index ee61563547..0e40030fff 100644 --- a/src/devices/Is31fl3730/Registers.cs +++ b/src/devices/Is31fl3730/Registers.cs @@ -12,36 +12,36 @@ public static class FunctionRegister /// Address for Configuration Register. /// public static byte Configuration = 0x0; - + /// /// Address for Matrix 1 Data Register. /// - public static byte Matrix1 = 0x1; - - /// - /// Address for Matrix 2 Data Register. - /// - public static byte Matrix2 = 0x0E; - + public static byte Matrix1 = 0x01; + /// /// Address for Update Column Register. /// public static byte UpdateColumn = 0x0C; - + /// /// Address for Lighting Effect Register. /// public static byte LightingEffect = 0x0D; - + + /// + /// Address for Matrix 2 Data Register. + /// + public static byte Matrix2 = 0x0E; + /// /// Address for PWM Register. /// public static byte Pwm = 0x19; - + /// /// Address for Reset Register. /// - public static byte Reset = 0x0C; + public static byte Reset = 0xFF; } /// diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 483a7e074f..5a2165ae97 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -8,20 +8,10 @@ using System.Threading; using Iot.Device.Display; -using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, BreakoutPair5x7.DefaultI2cAddress)); -BreakoutPair5x7 breakout = new(i2cDevice); - -breakout.Fill(0); -Thread.Sleep(100); -var mOne = breakout[0]; -var mTwo = breakout[1]; - -if (mOne is null || mTwo is null) -{ - return; -} - -var matrix = mOne; +// using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); +// DotMatrixBreakout10x7 matrix = new(i2cDevice); +MicroDotPhat30x7 matrix = new(); +matrix.Fill(0); // Dimensions int width = matrix.Width - 1; @@ -165,6 +155,15 @@ void WriteColumnPixels(int column, IEnumerable pixels, int value) Thread.Sleep(1000); matrix.Fill(0); -matrix.UpdateDecimalPoint(1); -Thread.Sleep(1000); +// For single matrix demo +// matrix.WriteDecimalPoint(1); +// Thread.Sleep(1000); + +// For Micro Dot pHat demo +foreach (var index in Enumerable.Range(0, 6)) +{ + matrix[index].WriteDecimalPoint(1); + Thread.Sleep(250); +} + matrix.Fill(0); From 5923b31b61ef87291c0222993386033ecc61e74f Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Fri, 16 Dec 2022 21:55:56 -0800 Subject: [PATCH 19/46] Add Length concept --- src/devices/Is31fl3730/DotMatrixBreakout10x7.cs | 13 +++++++++---- src/devices/Is31fl3730/MicroDotPhat30x7.cs | 5 +++++ src/devices/Is31fl3730/samples/Program.cs | 16 ++++++---------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs b/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs index 7ea85e0432..d349907483 100644 --- a/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs +++ b/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs @@ -32,8 +32,8 @@ public DotMatrixBreakout10x7(I2cDevice i2cDevice) _is31fl3730.Initialize(); _matrices = new DotMatrix5x7[] { - new DotMatrix5x7(_is31fl3730, 0), - new DotMatrix5x7(_is31fl3730, 1) + new DotMatrix5x7(_is31fl3730, 1), + new DotMatrix5x7(_is31fl3730, 0) }; } @@ -47,8 +47,8 @@ public DotMatrixBreakout10x7(Is31fl3730 is31fl3730) _is31fl3730 = is31fl3730; _matrices = new DotMatrix5x7[] { - new DotMatrix5x7(_is31fl3730, 0), - new DotMatrix5x7(_is31fl3730, 1) + new DotMatrix5x7(_is31fl3730, 1), + new DotMatrix5x7(_is31fl3730, 0) }; } @@ -72,6 +72,11 @@ public DotMatrixBreakout10x7(Is31fl3730 is31fl3730) /// public DotMatrix5x7 this[int matrix] => _matrices[matrix]; + /// + /// Length (or count) of matrices. + /// + public int Length => _matrices.Length; + /// /// Indexer for matrix pair. /// diff --git a/src/devices/Is31fl3730/MicroDotPhat30x7.cs b/src/devices/Is31fl3730/MicroDotPhat30x7.cs index ff56ff77d6..31c03f6e05 100644 --- a/src/devices/Is31fl3730/MicroDotPhat30x7.cs +++ b/src/devices/Is31fl3730/MicroDotPhat30x7.cs @@ -80,6 +80,11 @@ public MicroDotPhat30x7(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) /// public DotMatrix5x7 this[int matrix] => _matrices[matrix]; + /// + /// Length (or count) of matrices. + /// + public int Length => _matrices.Length; + /// /// Indexer for Micro Dot pHat matrix. /// diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 5a2165ae97..06ae7c11ea 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -8,9 +8,9 @@ using System.Threading; using Iot.Device.Display; -// using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); -// DotMatrixBreakout10x7 matrix = new(i2cDevice); -MicroDotPhat30x7 matrix = new(); +using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); +DotMatrixBreakout10x7 matrix = new(i2cDevice); +// MicroDotPhat30x7 matrix = new(); matrix.Fill(0); // Dimensions @@ -155,15 +155,11 @@ void WriteColumnPixels(int column, IEnumerable pixels, int value) Thread.Sleep(1000); matrix.Fill(0); -// For single matrix demo -// matrix.WriteDecimalPoint(1); -// Thread.Sleep(1000); - -// For Micro Dot pHat demo -foreach (var index in Enumerable.Range(0, 6)) +foreach (var index in Enumerable.Range(0, matrix.Length)) { matrix[index].WriteDecimalPoint(1); - Thread.Sleep(250); + Thread.Sleep(500); } +Thread.Sleep(250); matrix.Fill(0); From a900e7c6b0e9cce8f725906087690c89ae1a83f2 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Fri, 16 Dec 2022 22:01:01 -0800 Subject: [PATCH 20/46] Update ordering of matrices --- src/devices/Is31fl3730/MicroDotPhat30x7.cs | 8 ++++---- src/devices/Is31fl3730/samples/Program.cs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/devices/Is31fl3730/MicroDotPhat30x7.cs b/src/devices/Is31fl3730/MicroDotPhat30x7.cs index 31c03f6e05..99d9513038 100644 --- a/src/devices/Is31fl3730/MicroDotPhat30x7.cs +++ b/src/devices/Is31fl3730/MicroDotPhat30x7.cs @@ -33,8 +33,8 @@ public MicroDotPhat30x7() { I2cDevice i2cDevice = I2cDevice.Create(new(1, MatrixValues.Addresses[pair])); _pairs[pair] = new DotMatrixBreakout10x7(i2cDevice); - _matrices[pair * 2] = _pairs[pair][1]; - _matrices[pair * 2 + 1] = _pairs[pair][0]; + _matrices[pair * 2] = _pairs[pair][0]; + _matrices[pair * 2 + 1] = _pairs[pair][1]; } } @@ -60,8 +60,8 @@ public MicroDotPhat30x7(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) foreach (var pair in Enumerable.Range(0, 3)) { - _matrices[pair * 2] = _pairs[pair][1]; - _matrices[pair * 2 + 1] = _pairs[pair][0]; + _matrices[pair * 2] = _pairs[pair][0]; + _matrices[pair * 2 + 1] = _pairs[pair][1]; } } diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 06ae7c11ea..5809e86d4b 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -8,9 +8,9 @@ using System.Threading; using Iot.Device.Display; -using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); -DotMatrixBreakout10x7 matrix = new(i2cDevice); -// MicroDotPhat30x7 matrix = new(); +// using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); +// DotMatrixBreakout10x7 matrix = new(i2cDevice); +MicroDotPhat30x7 matrix = new(); matrix.Fill(0); // Dimensions From a3800dac582dd6f760bce78344c8fe513198978f Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Sat, 17 Dec 2022 09:17:02 -0800 Subject: [PATCH 21/46] Update README --- src/devices/Is31fl3730/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/Is31fl3730/README.md b/src/devices/Is31fl3730/README.md index f21a090159..04d8db95f0 100644 --- a/src/devices/Is31fl3730/README.md +++ b/src/devices/Is31fl3730/README.md @@ -1,4 +1,4 @@ - # IS31FL3730 -- LED Matrix Display Driver +# IS31FL3730 -- LED Matrix Display Driver The [IS31FL3730](https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf) is a compact LED driver that can drive one or two 8×8, 7×9, 6×10, or 5×11 dot matrix displays. The device can be programmed via an I2C compatible interface. From bcd92dc96bced3d9a034701a7d6caaf77d2fad67 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Sat, 17 Dec 2022 09:18:44 -0800 Subject: [PATCH 22/46] Change comment --- src/devices/Is31fl3730/samples/Program.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 5809e86d4b..06ae7c11ea 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -8,9 +8,9 @@ using System.Threading; using Iot.Device.Display; -// using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); -// DotMatrixBreakout10x7 matrix = new(i2cDevice); -MicroDotPhat30x7 matrix = new(); +using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); +DotMatrixBreakout10x7 matrix = new(i2cDevice); +// MicroDotPhat30x7 matrix = new(); matrix.Fill(0); // Dimensions From ac4d81944510e4cac426bfc6b6711877f3a9f9bb Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Sat, 17 Dec 2022 15:25:32 -0800 Subject: [PATCH 23/46] Switch to Slice syntax --- src/devices/Common/Common.csproj | 2 - src/devices/Common/IndexRange.cs | 252 ---------------------- src/devices/Common/RuntimeHelpers.cs | 43 ---- src/devices/Is31fl3730/Is31fl3730.cs | 2 +- src/devices/Is31fl3730/samples/Program.cs | 4 +- 5 files changed, 3 insertions(+), 300 deletions(-) delete mode 100644 src/devices/Common/IndexRange.cs delete mode 100644 src/devices/Common/RuntimeHelpers.cs diff --git a/src/devices/Common/Common.csproj b/src/devices/Common/Common.csproj index d937babd8d..10d8bb1fea 100644 --- a/src/devices/Common/Common.csproj +++ b/src/devices/Common/Common.csproj @@ -24,8 +24,6 @@ - - diff --git a/src/devices/Common/IndexRange.cs b/src/devices/Common/IndexRange.cs deleted file mode 100644 index 28f076d60f..0000000000 --- a/src/devices/Common/IndexRange.cs +++ /dev/null @@ -1,252 +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.Runtime.CompilerServices; - -// From: -// https://github.com/dotnet/runtime/blob/419e949d258ecee4c40a460fb09c66d974229623/src/libraries/System.Private.CoreLib/src/System/Index.cs -// https://github.com/dotnet/runtime/blob/419e949d258ecee4c40a460fb09c66d974229623/src/libraries/System.Private.CoreLib/src/System/Range.cs -// https://www.meziantou.net/assets/range.zip -namespace System -{ - /// Represent a type can be used to index a collection either from the start or the end. - /// - /// Index is used by the C# compiler to support the new index syntax - /// - /// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ; - /// int lastElement = someArray[^1]; // lastElement = 5 - /// - /// - public readonly struct Index : IEquatable - { - private readonly int _value; - - /// Construct an Index using a value and indicating if the index is from the start or from the end. - /// The index value. it has to be zero or positive number. - /// Indicating if the index is from the start or from the end. - /// - /// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Index(int value, bool fromEnd = false) - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative"); - } - - if (fromEnd) - { - _value = ~value; - } - else - { - _value = value; - } - } - - // The following private constructors mainly created for perf reason to avoid the checks - private Index(int value) - { - _value = value; - } - - /// Create an Index pointing at first element. - public static Index Start => new Index(0); - - /// Create an Index pointing at beyond last element. - public static Index End => new Index(~0); - - /// Create an Index from the start at the position indicated by the value. - /// The index value from the start. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Index FromStart(int value) - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative"); - } - - return new Index(value); - } - - /// Create an Index from the end at the position indicated by the value. - /// The index value from the end. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Index FromEnd(int value) - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative"); - } - - return new Index(~value); - } - - /// Returns the index value. - public int Value - { - get - { - if (_value < 0) - { - return ~_value; - } - else - { - return _value; - } - } - } - - /// Indicates whether the index is from the start or the end. - public bool IsFromEnd => _value < 0; - - /// Calculate the offset from the start using the giving collection length. - /// The length of the collection that the Index will be used with. length has to be a positive value - /// - /// For performance reason, we don't validate the input length parameter and the returned offset value against negative values. - /// we don't validate either the returned offset is greater than the input length. - /// It is expected Index will be used with collections which always have non negative length/count. If the returned offset is negative and - /// then used to index a collection will get out of range exception which will be same affect as the validation. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetOffset(int length) - { - var offset = _value; - if (IsFromEnd) - { - // offset = length - (~value) - // offset = length + (~(~value) + 1) - // offset = length + value + 1 - offset += length + 1; - } - - return offset; - } - - /// Indicates whether the current Index object is equal to another object of the same type. - /// An object to compare with this object - public override bool Equals(object? value) => value is Index && _value == ((Index)value)._value; - - /// Indicates whether the current Index object is equal to another Index object. - /// An object to compare with this object - public bool Equals(Index other) => _value == other._value; - - /// Returns the hash code for this instance. - public override int GetHashCode() => _value; - - /// Converts integer number to an Index. - public static implicit operator Index(int value) => FromStart(value); - - /// Converts the value of the current Index object to its equivalent string representation. - public override string ToString() - { - if (IsFromEnd) - { - return "^" + ((uint)Value).ToString(); - } - - return ((uint)Value).ToString(); - } - } - - /// Represent a range has start and end indexes. - /// - /// Range is used by the C# compiler to support the range syntax. - /// - /// int[] someArray = new int[5] { 1, 2, 3, 4, 5 }; - /// int[] subArray1 = someArray[0..2]; // { 1, 2 } - /// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 } - /// - /// - public readonly struct Range : IEquatable - { - /// Create a Range object starting from start index to the end of the collection. - public static Range StartAt(Index start) => new Range(start, Index.End); - - /// Create a Range object starting from first element in the collection to the end Index. - public static Range EndAt(Index end) => new Range(Index.Start, end); - - /// Create a Range object starting from first element to the end. - public static Range All => new Range(Index.Start, Index.End); - - /// Represent the inclusive start index of the Range. - public Index Start { get; } - - /// Represent the exclusive end index of the Range. - public Index End { get; } - - /// Construct a Range object using the start and end indexes. - /// Represent the inclusive start index of the range. - /// Represent the exclusive end index of the range. - public Range(Index start, Index end) - { - Start = start; - End = end; - } - - /// Indicates whether the current Range object is equal to another object of the same type. - /// An object to compare with this object - public override bool Equals(object? value) => - value is Range r && - r.Start.Equals(Start) && - r.End.Equals(End); - - /// Indicates whether the current Range object is equal to another Range object. - /// An object to compare with this object - public bool Equals(Range other) => other.Start.Equals(Start) && other.End.Equals(End); - - /// Returns the hash code for this instance. - public override int GetHashCode() - { - return Start.GetHashCode() * 31 + End.GetHashCode(); - } - - /// Converts the value of the current Range object to its equivalent string representation. - public override string ToString() - { - return Start + ".." + End; - } - - /// Calculate the start offset and length of range object using a collection length. - /// The length of the collection that the range will be used with. length has to be a positive value. - /// - /// For performance reason, we don't validate the input length parameter against negative values. - /// It is expected Range will be used with collections which always have non negative length/count. - /// We validate the range is inside the length scope though. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public (int Offset, int Length) GetOffsetAndLength(int length) - { - int start; - var startIndex = Start; - if (startIndex.IsFromEnd) - { - start = length - startIndex.Value; - } - else - { - start = startIndex.Value; - } - - int end; - var endIndex = End; - if (endIndex.IsFromEnd) - { - end = length - endIndex.Value; - } - else - { - end = endIndex.Value; - } - - if ((uint)end > (uint)length || (uint)start > (uint)end) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } - - return (start, end - start); - } - } -} diff --git a/src/devices/Common/RuntimeHelpers.cs b/src/devices/Common/RuntimeHelpers.cs deleted file mode 100644 index 9d3d611437..0000000000 --- a/src/devices/Common/RuntimeHelpers.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Runtime.CompilerServices -{ - // From: - // https://www.meziantou.net/assets/range.zip - internal static class RuntimeHelpers - { - /// - /// Slices the specified array using the specified range. - /// - public static T[] GetSubArray(T[] array, Range range) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - (int offset, int length) = range.GetOffsetAndLength(array.Length); - - if (default(T) != null || typeof(T[]) == array.GetType()) - { - // We know the type of the array to be exactly T[]. - if (length == 0) - { - return Array.Empty(); - } - - var dest = new T[length]; - Array.Copy(array, offset, dest, 0, length); - return dest; - } - else - { - // The array is actually a U[] where U:T. - var dest = (T[])Array.CreateInstance(array.GetType().GetElementType(), length); - Array.Copy(array, offset, dest, 0, length); - return dest; - } - } - } -} diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 9ea5def10b..10a15b7520 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -349,7 +349,7 @@ private void Write(byte address, ReadOnlySpan value) { Span data = stackalloc byte[value.Length + 1]; data[0] = address; - value.CopyTo(data[1..]); + value.CopyTo(data.Slice(1)); _i2cDevice.Write(data); } diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 06ae7c11ea..1b5d30b5a9 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -11,14 +11,14 @@ using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); DotMatrixBreakout10x7 matrix = new(i2cDevice); // MicroDotPhat30x7 matrix = new(); -matrix.Fill(0); - // Dimensions int width = matrix.Width - 1; int height = matrix.Height - 1; int halfWidth = matrix.Width / 2; int halfHeight = matrix.Height / 2; +matrix.Fill(0); + matrix[0, 0] = 1; matrix[0, height] = 1; matrix[width, 0] = 1; From 230a2121d8ba27b7110a2caa9004293fa24bf5f1 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Sun, 18 Dec 2022 10:22:41 -0800 Subject: [PATCH 24/46] Remove magic numbers --- src/devices/Is31fl3730/DotMatrix5x7.cs | 4 +-- .../Is31fl3730/DotMatrixBreakout10x7.cs | 4 +-- src/devices/Is31fl3730/Is31fl3730.cs | 9 ++----- src/devices/Is31fl3730/MatrixValues.cs | 11 +++++++- src/devices/Is31fl3730/MicroDotPhat30x7.cs | 26 ++++++++++++------- src/devices/Is31fl3730/samples/Program.cs | 6 ++--- 6 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/devices/Is31fl3730/DotMatrix5x7.cs b/src/devices/Is31fl3730/DotMatrix5x7.cs index 7f810f33f8..e32532f40a 100644 --- a/src/devices/Is31fl3730/DotMatrix5x7.cs +++ b/src/devices/Is31fl3730/DotMatrix5x7.cs @@ -39,12 +39,12 @@ public DotMatrix5x7(Is31fl3730 is31fl3730, int matrix) /// /// Width of LED matrix (x axis). /// - public readonly int Width = 5; + public readonly int Width = MatrixValues.Width; /// /// Height of LED matrix (y axis). /// - public readonly int Height = 7; + public readonly int Height = MatrixValues.Height; /// /// Fill matrix (0 is dark; 1 is lit). diff --git a/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs b/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs index d349907483..25ff119e5f 100644 --- a/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs +++ b/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs @@ -60,12 +60,12 @@ public DotMatrixBreakout10x7(Is31fl3730 is31fl3730) /// /// Width of LED matrix (x axis). /// - public readonly int Width = 10; + public readonly int Width = MatrixValues.Width * 2; /// /// Height of LED matrix (y axis). /// - public readonly int Height = 7; + public readonly int Height = MatrixValues.Height; /// /// Indexer for matrices. diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 10a15b7520..9671270c17 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -62,11 +62,6 @@ public Is31fl3730(I2cDevice i2cDevice) /// public const int DefaultI2cAddress = 0x61; - /// - /// Supported I2C addresses for device. - /// - public static readonly int[] SupportedI2cAddresses = new int[] { DefaultI2cAddress, 0x62, 0x63 }; - /// /// Brightness of LED matrix (override default value (128; max brightness); set before calling Initialize method). /// @@ -232,8 +227,8 @@ x x */ if (matrix > 1 || - x > 4 || - y > 6) + x >= MatrixValues.Height || + y >= MatrixValues.Width) { throw new ArgumentException("Argument out of range."); } diff --git a/src/devices/Is31fl3730/MatrixValues.cs b/src/devices/Is31fl3730/MatrixValues.cs index b5c8b10366..39815bf8e1 100644 --- a/src/devices/Is31fl3730/MatrixValues.cs +++ b/src/devices/Is31fl3730/MatrixValues.cs @@ -8,6 +8,16 @@ namespace Iot.Device.Display /// public static class MatrixValues { + /// + /// Width (x-axis) of LED Dot Matrix. + /// + public static int Width = 5; + + /// + /// Height (y-axis) of LED Dot Matrix. + /// + public static int Height = 7; + /// /// Arbitrary 8-bit value to write to Update Column Register, as required by datasheet. /// @@ -37,6 +47,5 @@ public static class MatrixValues /// I2C addresses for Micro Dot pHat, right to left. /// public static int[] Addresses = new int[] { 0x63, 0x62, 0x61 }; - } } diff --git a/src/devices/Is31fl3730/MicroDotPhat30x7.cs b/src/devices/Is31fl3730/MicroDotPhat30x7.cs index 99d9513038..e31a7d48c5 100644 --- a/src/devices/Is31fl3730/MicroDotPhat30x7.cs +++ b/src/devices/Is31fl3730/MicroDotPhat30x7.cs @@ -68,12 +68,12 @@ public MicroDotPhat30x7(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) /// /// Width of LED matrix (x axis). /// - public readonly int Width = 30; + public readonly int Width = MatrixValues.Width * 6; /// /// Height of LED matrix (y axis). /// - public readonly int Height = 7; + public readonly int Height = MatrixValues.Height; /// /// Indexer for matrices. @@ -92,10 +92,7 @@ public MicroDotPhat30x7(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) { get { - if (x >= 30 || y > 6) - { - throw new ArgumentException("Input value out of range."); - } + CheckDimensions(x, y); int matrix = x % 5; int modx = x - (matrix * 5); @@ -103,10 +100,7 @@ public MicroDotPhat30x7(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) } set { - if (x >= 30 || y > 6) - { - throw new ArgumentException("Input value out of range."); - } + CheckDimensions(x, y); int matrix = x / 5; int modx = x - (matrix * 5); @@ -124,5 +118,17 @@ public void Fill(int value) pair.Fill(value); } } + + private void CheckDimensions(int x, int y) + { + if (x >= Width) + { + throw new ArgumentException($"{nameof(x)} value ({x}) out of range."); + } + else if (y >= Height) + { + throw new ArgumentException($"{nameof(y)} value ({y}) out of range."); + } + } } } diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 1b5d30b5a9..58d15db0ff 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -8,9 +8,9 @@ using System.Threading; using Iot.Device.Display; -using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); -DotMatrixBreakout10x7 matrix = new(i2cDevice); -// MicroDotPhat30x7 matrix = new(); +// using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); +// DotMatrixBreakout10x7 matrix = new(i2cDevice); +MicroDotPhat30x7 matrix = new(); // Dimensions int width = matrix.Width - 1; int height = matrix.Height - 1; From 57eacd2729251fbd97a7b7262244522665ff5d4d Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 19 Dec 2022 10:39:15 -0800 Subject: [PATCH 25/46] Remove code duplication --- src/devices/Is31fl3730/DotMatrix.cs | 115 ++++++++++++++++++ ...MatrixBreakout10x7.cs => DotMatrix10x7.cs} | 62 +++------- src/devices/Is31fl3730/DotMatrix5x7.cs | 16 +-- src/devices/Is31fl3730/Is31fl3730.cs | 30 ++++- src/devices/Is31fl3730/Is31fl3730.csproj | 3 +- src/devices/Is31fl3730/MatrixValues.cs | 15 --- src/devices/Is31fl3730/MicroDotPhat30x7.cs | 85 ++++--------- src/devices/Is31fl3730/samples/Program.cs | 6 +- 8 files changed, 199 insertions(+), 133 deletions(-) create mode 100644 src/devices/Is31fl3730/DotMatrix.cs rename src/devices/Is31fl3730/{DotMatrixBreakout10x7.cs => DotMatrix10x7.cs} (51%) diff --git a/src/devices/Is31fl3730/DotMatrix.cs b/src/devices/Is31fl3730/DotMatrix.cs new file mode 100644 index 0000000000..8f82e8ddd6 --- /dev/null +++ b/src/devices/Is31fl3730/DotMatrix.cs @@ -0,0 +1,115 @@ +// 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; +using System.Collections.Generic; +using System.Device.I2c; +using System.Threading; + +namespace Iot.Device.Display +{ + /// + /// Represents a virtual LED Matrix. + /// + // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf + // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout + // Related repo: https://github.com/pimoroni/microdot-phat + public class DotMatrix + { + private readonly DotMatrix5x7[] _matrices; + + /// + /// Initialize virtual Dot Matrix. + /// + /// The to create with. + public DotMatrix(DotMatrix5x7[] matrices) + { + _matrices = matrices; + Width = matrices.Length * DotMatrix5x7.Width; + } + + /// + /// Width of LED matrix (x axis). + /// + public readonly int Width; + + /// + /// Height of LED matrix (y axis). + /// + public readonly int Height = DotMatrix5x7.Height; + + /// + /// Indexer for matrices. + /// + public DotMatrix5x7 this[int matrix] => _matrices[matrix]; + + /// + /// Length (or count) of matrices. + /// + public int Length => _matrices.Length; + + /// + /// Indexer for matrix pair. + /// + public int this[int x, int y] + { + get + { + var (matrixIndex, index) = GetMatrixIndex(x, y); + return _matrices[matrixIndex][index, y]; + } + set + { + var (matrixIndex, index) = GetMatrixIndex(x, y); + _matrices[matrixIndex][index, y] = value; + } + } + + /// + /// Fill All LEDs. + /// + public void Fill(int value) + { + foreach (DotMatrix5x7 matrix in _matrices) + { + matrix.Fill(value); + } + } + + private (int MatrixIndex, int Index) GetMatrixIndex(int x, int y) + { + if (x >= Width || x < 0) + { + throw new ArgumentException($"{nameof(x)} value ({x}) out of range."); + } + + if (y >= Height || y < 0) + { + throw new ArgumentException($"{nameof(y)} value ({y}) out of range."); + } + + int matrixIndex = x / DotMatrix5x7.Width; + int index = x % DotMatrix5x7.Width; + + if (index >= 5) + { + throw new ArgumentException($"{nameof(x)} value ({x}) out of range."); + } + + return (matrixIndex, index); + } + + /// + /// Default Is31fl3730 initialization + /// + public static Is31fl3730 Initialize(I2cDevice i2cDevice) + { + i2cDevice = i2cDevice ?? throw new ArgumentException($"{nameof(i2cDevice)} is null."); + Is31fl3730 is31fl3730 = new(i2cDevice); + is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; + is31fl3730.Initialize(); + return is31fl3730; + } + } +} diff --git a/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs b/src/devices/Is31fl3730/DotMatrix10x7.cs similarity index 51% rename from src/devices/Is31fl3730/DotMatrixBreakout10x7.cs rename to src/devices/Is31fl3730/DotMatrix10x7.cs index 25ff119e5f..b7c2d98af5 100644 --- a/src/devices/Is31fl3730/DotMatrixBreakout10x7.cs +++ b/src/devices/Is31fl3730/DotMatrix10x7.cs @@ -15,41 +15,34 @@ namespace Iot.Device.Display // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat - public class DotMatrixBreakout10x7 + public class DotMatrix10x7 { - private readonly DotMatrix5x7[] _matrices; - private Is31fl3730 _is31fl3730; + private readonly DotMatrix _matrix; /// /// Initialize Dot Matrix Breakout IS31FL3730 device. /// /// The to create with. - public DotMatrixBreakout10x7(I2cDevice i2cDevice) + public DotMatrix10x7(I2cDevice i2cDevice) + : this(DotMatrix.Initialize(i2cDevice)) { - i2cDevice = i2cDevice ?? throw new ArgumentException($"{nameof(i2cDevice)} is null."); - _is31fl3730 = new(i2cDevice); - _is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; - _is31fl3730.Initialize(); - _matrices = new DotMatrix5x7[] - { - new DotMatrix5x7(_is31fl3730, 1), - new DotMatrix5x7(_is31fl3730, 0) - }; } /// /// Initialize Dot Matrix Breakout IS31FL3730 device. /// /// The to create with. - public DotMatrixBreakout10x7(Is31fl3730 is31fl3730) + public DotMatrix10x7(Is31fl3730 is31fl3730) { is31fl3730 = is31fl3730 ?? throw new ArgumentException($"{nameof(is31fl3730)} is null."); - _is31fl3730 = is31fl3730; - _matrices = new DotMatrix5x7[] + var matrices = new DotMatrix5x7[] { - new DotMatrix5x7(_is31fl3730, 1), - new DotMatrix5x7(_is31fl3730, 0) + is31fl3730[1], + is31fl3730[0] }; + + _matrix = new DotMatrix(matrices); + Width = _matrix.Width; } /// @@ -60,54 +53,35 @@ public DotMatrixBreakout10x7(Is31fl3730 is31fl3730) /// /// Width of LED matrix (x axis). /// - public readonly int Width = MatrixValues.Width * 2; + public readonly int Width; /// /// Height of LED matrix (y axis). /// - public readonly int Height = MatrixValues.Height; + public readonly int Height = DotMatrix5x7.Height; /// /// Indexer for matrices. /// - public DotMatrix5x7 this[int matrix] => _matrices[matrix]; + public DotMatrix5x7 this[int matrix] => _matrix[matrix]; /// /// Length (or count) of matrices. /// - public int Length => _matrices.Length; + public int Length => _matrix.Length; /// /// Indexer for matrix pair. /// public int this[int x, int y] { - get => x switch - { - < 5 => this[0][x, y], - < 10 => this[1][x - 5, y], - _ => throw new ArgumentException($"{nameof(x)} value out of range") - }; - set - { - if (x < 5) - { - this[0][x, y] = value; - } - else if (x < 10) - { - this[1][x - 5, y] = value; - } - else - { - throw new ArgumentException($"{nameof(x)} value out of range"); - } - } + get => _matrix[x, y]; + set => _matrix[x, y] = value; } /// /// Fill All LEDs. /// - public void Fill(int value) => _is31fl3730.Fill(value); + public void Fill(int value) => _matrix.Fill(value); } } diff --git a/src/devices/Is31fl3730/DotMatrix5x7.cs b/src/devices/Is31fl3730/DotMatrix5x7.cs index e32532f40a..355f7274ef 100644 --- a/src/devices/Is31fl3730/DotMatrix5x7.cs +++ b/src/devices/Is31fl3730/DotMatrix5x7.cs @@ -37,23 +37,23 @@ public DotMatrix5x7(Is31fl3730 is31fl3730, int matrix) } /// - /// Width of LED matrix (x axis). + /// Fill matrix (0 is dark; 1 is lit). /// - public readonly int Width = MatrixValues.Width; + public void Fill(int value) => _is31fl3730.Fill(_matrix, value); /// - /// Height of LED matrix (y axis). + /// Fill matrix (0 is dark; 1 is lit). /// - public readonly int Height = MatrixValues.Height; + public void WriteDecimalPoint(int value) => _is31fl3730.WriteDecimalPoint(_matrix, value); /// - /// Fill matrix (0 is dark; 1 is lit). + /// Width of LED matrix (x axis). /// - public void Fill(int value) => _is31fl3730.Fill(_matrix, value); + public static readonly int Width = 5; /// - /// Fill matrix (0 is dark; 1 is lit). + /// Height of LED matrix (y axis). /// - public void WriteDecimalPoint(int value) => _is31fl3730.WriteDecimalPoint(_matrix, value); + public static readonly int Height = 7; } } diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 9671270c17..986baaa833 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -87,16 +87,23 @@ public Is31fl3730(I2cDevice i2cDevice) /// public bool BufferingEnabled { get; set; } = true; + /// + /// Indexer for matrices. + /// + public DotMatrix5x7 this[int index] => GetMatrix(index); + /// /// Initialize LED driver. /// public void Initialize() { + // Set size of matrix if (MatrixMode > 0) { _configurationValue |= (int)MatrixMode; } + // Set number of and which supported matrices (either or both) if (DisplayMode > 0) { _enabled[0] = DisplayMode is DisplayMode.MatrixOneOnly or DisplayMode.MatrixOneAndTwo; @@ -108,16 +115,19 @@ public void Initialize() _enabled[0] = true; } + // If (non-default) configurations values are set, write to device if (_configurationValue > 0) { Write(FunctionRegister.Configuration, (byte)_configurationValue); } + // Set current value if (Current > 0) { Write(FunctionRegister.LightingEffect, (byte)Current); } + // Set brightness value if (Brightness > 0) { Write(FunctionRegister.Pwm, (byte)Brightness); @@ -227,8 +237,8 @@ x x */ if (matrix > 1 || - x >= MatrixValues.Height || - y >= MatrixValues.Width) + x >= DotMatrix5x7.Width || + y >= DotMatrix5x7.Height) { throw new ArgumentException("Argument out of range."); } @@ -284,11 +294,11 @@ public void Fill(int matrix, int value) /// public void Fill(int value) { - foreach (int i in Range(0, 2)) + foreach (int index in Range(0, 2)) { - if (_enabled[i]) + if (_enabled[index]) { - Fill(i, value); + Fill(index, value); } } } @@ -380,5 +390,15 @@ private void AutoFlush(int matrix) Flush(matrix); } } + + private DotMatrix5x7 GetMatrix(int index) + { + if (index is < 0 or > 1) + { + throw new ArgumentException($"{nameof(index)} ({index}) is out of range."); + } + + return new DotMatrix5x7(this, index); + } } } diff --git a/src/devices/Is31fl3730/Is31fl3730.csproj b/src/devices/Is31fl3730/Is31fl3730.csproj index 9151f68d22..69e12ef66e 100644 --- a/src/devices/Is31fl3730/Is31fl3730.csproj +++ b/src/devices/Is31fl3730/Is31fl3730.csproj @@ -13,8 +13,9 @@ - + + \ No newline at end of file diff --git a/src/devices/Is31fl3730/MatrixValues.cs b/src/devices/Is31fl3730/MatrixValues.cs index 39815bf8e1..a1b605d971 100644 --- a/src/devices/Is31fl3730/MatrixValues.cs +++ b/src/devices/Is31fl3730/MatrixValues.cs @@ -8,16 +8,6 @@ namespace Iot.Device.Display /// public static class MatrixValues { - /// - /// Width (x-axis) of LED Dot Matrix. - /// - public static int Width = 5; - - /// - /// Height (y-axis) of LED Dot Matrix. - /// - public static int Height = 7; - /// /// Arbitrary 8-bit value to write to Update Column Register, as required by datasheet. /// @@ -42,10 +32,5 @@ public static class MatrixValues /// Matrix two decimal point row. /// public static byte MatrixTwoDecimalRow = 7; - - /// - /// I2C addresses for Micro Dot pHat, right to left. - /// - public static int[] Addresses = new int[] { 0x63, 0x62, 0x61 }; } } diff --git a/src/devices/Is31fl3730/MicroDotPhat30x7.cs b/src/devices/Is31fl3730/MicroDotPhat30x7.cs index e31a7d48c5..1344456b02 100644 --- a/src/devices/Is31fl3730/MicroDotPhat30x7.cs +++ b/src/devices/Is31fl3730/MicroDotPhat30x7.cs @@ -19,23 +19,17 @@ namespace Iot.Device.Display // Related repo: https://github.com/pimoroni/microdot-phat public class MicroDotPhat30x7 { - private DotMatrixBreakout10x7[] _pairs; - private DotMatrix5x7[] _matrices = new DotMatrix5x7[6]; + private DotMatrix _matrix; /// /// Initialize Micro Dot pHAT IS31FL3730 device. /// - public MicroDotPhat30x7() + /// The first Dot Matrix pair. + /// The first Dot Matrix pair. + /// The first Dot Matrix pair. + public MicroDotPhat30x7(I2cDevice first, I2cDevice second, I2cDevice third) + : this(DotMatrix.Initialize(first), DotMatrix.Initialize(second), DotMatrix.Initialize(third)) { - _pairs = new DotMatrixBreakout10x7[3]; - - foreach (var pair in Enumerable.Range(0, 3)) - { - I2cDevice i2cDevice = I2cDevice.Create(new(1, MatrixValues.Addresses[pair])); - _pairs[pair] = new DotMatrixBreakout10x7(i2cDevice); - _matrices[pair * 2] = _pairs[pair][0]; - _matrices[pair * 2 + 1] = _pairs[pair][1]; - } } /// @@ -51,84 +45,57 @@ public MicroDotPhat30x7(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) throw new ArgumentException($"Input argument is null."); } - _pairs = new DotMatrixBreakout10x7[] + var matrices = new DotMatrix5x7[] { - new(first), - new(second), - new(third) + first[1], + first[0], + second[1], + second[0], + third[1], + third[0], }; - foreach (var pair in Enumerable.Range(0, 3)) - { - _matrices[pair * 2] = _pairs[pair][0]; - _matrices[pair * 2 + 1] = _pairs[pair][1]; - } + _matrix = new DotMatrix(matrices); + Width = _matrix.Width; } /// /// Width of LED matrix (x axis). /// - public readonly int Width = MatrixValues.Width * 6; + public readonly int Width; /// /// Height of LED matrix (y axis). /// - public readonly int Height = MatrixValues.Height; + public readonly int Height = DotMatrix5x7.Height; /// /// Indexer for matrices. /// - public DotMatrix5x7 this[int matrix] => _matrices[matrix]; + public DotMatrix5x7 this[int matrix] => _matrix[matrix]; /// /// Length (or count) of matrices. /// - public int Length => _matrices.Length; + public int Length => _matrix.Length; /// /// Indexer for Micro Dot pHat matrix. /// public int this[int x, int y] { - get - { - CheckDimensions(x, y); - - int matrix = x % 5; - int modx = x - (matrix * 5); - return this[matrix][modx, y]; - } - set - { - CheckDimensions(x, y); - - int matrix = x / 5; - int modx = x - (matrix * 5); - this[matrix][modx, y] = value; - } + get => _matrix[x, y]; + set => _matrix[x, y] = value; } /// /// Fill All LEDs. /// - public void Fill(int value) - { - foreach (var pair in _pairs) - { - pair.Fill(value); - } - } + public void Fill(int value) => _matrix.Fill(value); - private void CheckDimensions(int x, int y) - { - if (x >= Width) - { - throw new ArgumentException($"{nameof(x)} value ({x}) out of range."); - } - else if (y >= Height) - { - throw new ArgumentException($"{nameof(y)} value ({y}) out of range."); - } - } + /// + /// I2C addresses for Micro Dot pHat, right to left. + /// + public static int[] Addresses = new int[] { 0x63, 0x62, 0x61 }; } } diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 58d15db0ff..9f20998559 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -10,7 +10,11 @@ // using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); // DotMatrixBreakout10x7 matrix = new(i2cDevice); -MicroDotPhat30x7 matrix = new(); +using I2cDevice first = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[0])); +using I2cDevice second = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[1])); +using I2cDevice third = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[2])); +MicroDotPhat30x7 matrix = new(first, second, third); + // Dimensions int width = matrix.Width - 1; int height = matrix.Height - 1; From 096bdce3877a44ebe60f7d7e397e0e9c0a01e890 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 19 Dec 2022 10:43:44 -0800 Subject: [PATCH 26/46] Fix type name --- src/devices/Is31fl3730/samples/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 9f20998559..7efa76a8db 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -8,8 +8,8 @@ using System.Threading; using Iot.Device.Display; -// using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrixBreakout10x7.DefaultI2cAddress)); -// DotMatrixBreakout10x7 matrix = new(i2cDevice); +// using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrix10x7.DefaultI2cAddress)); +// DotMatrix10x7 matrix = new(i2cDevice); using I2cDevice first = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[0])); using I2cDevice second = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[1])); using I2cDevice third = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[2])); From 0992e82b6bd47715fd6b869d444715baa5f2b3de Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 19 Dec 2022 11:20:06 -0800 Subject: [PATCH 27/46] Update README --- src/devices/Is31fl3730/README.md | 53 +++++++++++++++++++++-- src/devices/Is31fl3730/samples/Program.cs | 5 ++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/devices/Is31fl3730/README.md b/src/devices/Is31fl3730/README.md index 04d8db95f0..ea64a8f109 100644 --- a/src/devices/Is31fl3730/README.md +++ b/src/devices/Is31fl3730/README.md @@ -4,10 +4,57 @@ The [IS31FL3730](https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf) This binding is similar to the Python version in [pimoroni/microdot-phat](https://github.com/pimoroni/microdot-phat). +It is demonstrated in [samples/Program.cs](samples/Program.cs). + ## Micro Dot pHAT -An unashamedly old school LED matrix display board, made up of six LED matrices each 5x7 pixels (for an effective display area of 30x7) plus a decimal point, using the beautiful little Lite-On LTP-305 matrices. +The [Micro Dot pHat](https://shop.pimoroni.com/products/microdot-phat) is an unashamedly old school LED matrix display board, made up of six LED matrices each 5x7 pixels (for an effective display area of 30x7) plus a decimal point, using the beautiful little Lite-On LTP-305 matrices. + + + +The following code demonstrates how to control the Micro Dot pHAT. + + +```csharp +using I2cDevice first = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[0])); +using I2cDevice second = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[1])); +using I2cDevice third = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[2])); +MicroDotPhat30x7 matrix = new(first, second, third); + +matrix.Fill(0); + +matrix[0, 0] = 1; +matrix[0, 6] = 1; +matrix[29, 0] = 1; +matrix[29, 6] = 1; +Thread.Sleep(500); + +matrix.Fill(255); +Thread.Sleep(1000); + +matrix.Fill(0); +``` + +## LED Dot Matrix Breakout + +The [LED Dot Matrix Breakout](https://shop.pimoroni.com/products/led-dot-matrix-breakout) is perfect for readouts that involve two numbers or letters - like countdown timers, percentage readouts, or country codes. + + + +The following code demonstrates how to control the LED Dot Matrix Breakout. + +```csharp +using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrix10x7.DefaultI2cAddress)); +DotMatrix10x7 matrix = new(i2cDevice); + +matrix[0, 0] = 1; +matrix[0, 6] = 1; +matrix[9, 0] = 1; +matrix[9, 6] = 1; +Thread.Sleep(500); - +matrix.Fill(255); +Thread.Sleep(1000); -You can write the following code to control them or checkout a larger sample. +matrix.Fill(0); +``` diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 7efa76a8db..d238f8de52 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -27,8 +27,11 @@ matrix[0, height] = 1; matrix[width, 0] = 1; matrix[width, height] = 1; - Thread.Sleep(500); + +matrix.Fill(255); +Thread.Sleep(1000); + matrix.Fill(0); // Set pixel in the origin 0, 0 position. From 6322a241811c5d19c826e87b706521b2db64df53 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 19 Dec 2022 16:53:43 -0800 Subject: [PATCH 28/46] Switch dimensional fields to properties --- src/devices/Is31fl3730/DotMatrix.cs | 5 +++-- src/devices/Is31fl3730/DotMatrix10x7.cs | 5 +++-- src/devices/Is31fl3730/MicroDotPhat30x7.cs | 5 +++-- src/devices/Is31fl3730/samples/Program.cs | 2 ++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/devices/Is31fl3730/DotMatrix.cs b/src/devices/Is31fl3730/DotMatrix.cs index 8f82e8ddd6..f8c11d0829 100644 --- a/src/devices/Is31fl3730/DotMatrix.cs +++ b/src/devices/Is31fl3730/DotMatrix.cs @@ -27,17 +27,18 @@ public DotMatrix(DotMatrix5x7[] matrices) { _matrices = matrices; Width = matrices.Length * DotMatrix5x7.Width; + Height = DotMatrix5x7.Height; } /// /// Width of LED matrix (x axis). /// - public readonly int Width; + public int Width { get; } /// /// Height of LED matrix (y axis). /// - public readonly int Height = DotMatrix5x7.Height; + public int Height { get; } /// /// Indexer for matrices. diff --git a/src/devices/Is31fl3730/DotMatrix10x7.cs b/src/devices/Is31fl3730/DotMatrix10x7.cs index b7c2d98af5..fccaad5bca 100644 --- a/src/devices/Is31fl3730/DotMatrix10x7.cs +++ b/src/devices/Is31fl3730/DotMatrix10x7.cs @@ -43,6 +43,7 @@ public DotMatrix10x7(Is31fl3730 is31fl3730) _matrix = new DotMatrix(matrices); Width = _matrix.Width; + Height = _matrix.Height; } /// @@ -53,12 +54,12 @@ public DotMatrix10x7(Is31fl3730 is31fl3730) /// /// Width of LED matrix (x axis). /// - public readonly int Width; + public int Width { get; } /// /// Height of LED matrix (y axis). /// - public readonly int Height = DotMatrix5x7.Height; + public int Height { get; } /// /// Indexer for matrices. diff --git a/src/devices/Is31fl3730/MicroDotPhat30x7.cs b/src/devices/Is31fl3730/MicroDotPhat30x7.cs index 1344456b02..24faa60b51 100644 --- a/src/devices/Is31fl3730/MicroDotPhat30x7.cs +++ b/src/devices/Is31fl3730/MicroDotPhat30x7.cs @@ -57,17 +57,18 @@ public MicroDotPhat30x7(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) _matrix = new DotMatrix(matrices); Width = _matrix.Width; + Height = _matrix.Height; } /// /// Width of LED matrix (x axis). /// - public readonly int Width; + public int Width { get; } /// /// Height of LED matrix (y axis). /// - public readonly int Height = DotMatrix5x7.Height; + public int Height { get; } /// /// Indexer for matrices. diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index d238f8de52..102fec378d 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -8,8 +8,10 @@ using System.Threading; using Iot.Device.Display; +// For LED Dot Matrix Breakouts // using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrix10x7.DefaultI2cAddress)); // DotMatrix10x7 matrix = new(i2cDevice); +// For Micro Dot pHat using I2cDevice first = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[0])); using I2cDevice second = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[1])); using I2cDevice third = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[2])); From 0b2434482f90d4d12621a840f62584d70658542f Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 19 Dec 2022 19:24:23 -0800 Subject: [PATCH 29/46] Remove code by subclassing --- src/devices/Is31fl3730/DotMatrix10x7.cs | 53 ++++--------------- src/devices/Is31fl3730/MicroDotPhat30x7.cs | 59 +++++----------------- src/devices/Is31fl3730/samples/Program.cs | 6 +-- 3 files changed, 24 insertions(+), 94 deletions(-) diff --git a/src/devices/Is31fl3730/DotMatrix10x7.cs b/src/devices/Is31fl3730/DotMatrix10x7.cs index fccaad5bca..65bb7b7d04 100644 --- a/src/devices/Is31fl3730/DotMatrix10x7.cs +++ b/src/devices/Is31fl3730/DotMatrix10x7.cs @@ -15,10 +15,8 @@ namespace Iot.Device.Display // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat - public class DotMatrix10x7 + public class DotMatrix10x7 : DotMatrix { - private readonly DotMatrix _matrix; - /// /// Initialize Dot Matrix Breakout IS31FL3730 device. /// @@ -33,17 +31,8 @@ public DotMatrix10x7(I2cDevice i2cDevice) /// /// The to create with. public DotMatrix10x7(Is31fl3730 is31fl3730) + : base(Initialize(is31fl3730)) { - is31fl3730 = is31fl3730 ?? throw new ArgumentException($"{nameof(is31fl3730)} is null."); - var matrices = new DotMatrix5x7[] - { - is31fl3730[1], - is31fl3730[0] - }; - - _matrix = new DotMatrix(matrices); - Width = _matrix.Width; - Height = _matrix.Height; } /// @@ -51,38 +40,14 @@ public DotMatrix10x7(Is31fl3730 is31fl3730) /// public const int DefaultI2cAddress = 0x61; - /// - /// Width of LED matrix (x axis). - /// - public int Width { get; } - - /// - /// Height of LED matrix (y axis). - /// - public int Height { get; } - - /// - /// Indexer for matrices. - /// - public DotMatrix5x7 this[int matrix] => _matrix[matrix]; - - /// - /// Length (or count) of matrices. - /// - public int Length => _matrix.Length; - - /// - /// Indexer for matrix pair. - /// - public int this[int x, int y] + private static DotMatrix5x7[] Initialize(Is31fl3730 is31fl3730) { - get => _matrix[x, y]; - set => _matrix[x, y] = value; + is31fl3730 = is31fl3730 ?? throw new ArgumentException($"{nameof(is31fl3730)} is null"); + return new DotMatrix5x7[] + { + is31fl3730[1], + is31fl3730[0] + }; } - - /// - /// Fill All LEDs. - /// - public void Fill(int value) => _matrix.Fill(value); } } diff --git a/src/devices/Is31fl3730/MicroDotPhat30x7.cs b/src/devices/Is31fl3730/MicroDotPhat30x7.cs index 24faa60b51..d18fc797fe 100644 --- a/src/devices/Is31fl3730/MicroDotPhat30x7.cs +++ b/src/devices/Is31fl3730/MicroDotPhat30x7.cs @@ -17,10 +17,8 @@ namespace Iot.Device.Display // Product: https://shop.pimoroni.com/products/microdot-phat // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat - public class MicroDotPhat30x7 + public class MicroDotPhat30x7 : DotMatrix { - private DotMatrix _matrix; - /// /// Initialize Micro Dot pHAT IS31FL3730 device. /// @@ -39,13 +37,23 @@ public MicroDotPhat30x7(I2cDevice first, I2cDevice second, I2cDevice third) /// The first Dot Matrix pair. /// The first Dot Matrix pair. public MicroDotPhat30x7(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) + : base(Initialize(first, second, third)) + { + } + + /// + /// I2C addresses for Micro Dot pHat, left to right. + /// + public static int[] I2cAddresses = new int[] { 0x63, 0x62, 0x61 }; + + private static DotMatrix5x7[] Initialize(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) { if (first is null || second is null || third is null) { throw new ArgumentException($"Input argument is null."); } - var matrices = new DotMatrix5x7[] + return new DotMatrix5x7[] { first[1], first[0], @@ -54,49 +62,6 @@ public MicroDotPhat30x7(Is31fl3730 first, Is31fl3730 second, Is31fl3730 third) third[1], third[0], }; - - _matrix = new DotMatrix(matrices); - Width = _matrix.Width; - Height = _matrix.Height; } - - /// - /// Width of LED matrix (x axis). - /// - public int Width { get; } - - /// - /// Height of LED matrix (y axis). - /// - public int Height { get; } - - /// - /// Indexer for matrices. - /// - public DotMatrix5x7 this[int matrix] => _matrix[matrix]; - - /// - /// Length (or count) of matrices. - /// - public int Length => _matrix.Length; - - /// - /// Indexer for Micro Dot pHat matrix. - /// - public int this[int x, int y] - { - get => _matrix[x, y]; - set => _matrix[x, y] = value; - } - - /// - /// Fill All LEDs. - /// - public void Fill(int value) => _matrix.Fill(value); - - /// - /// I2C addresses for Micro Dot pHat, right to left. - /// - public static int[] Addresses = new int[] { 0x63, 0x62, 0x61 }; } } diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 102fec378d..6bcd05b5f5 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -12,9 +12,9 @@ // using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(busId: 1, DotMatrix10x7.DefaultI2cAddress)); // DotMatrix10x7 matrix = new(i2cDevice); // For Micro Dot pHat -using I2cDevice first = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[0])); -using I2cDevice second = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[1])); -using I2cDevice third = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[2])); +using I2cDevice first = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.I2cAddresses[0])); +using I2cDevice second = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.I2cAddresses[1])); +using I2cDevice third = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.I2cAddresses[2])); MicroDotPhat30x7 matrix = new(first, second, third); // Dimensions From 62459d757b4401532ac356643d07547610ebca69 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 19 Dec 2022 19:38:31 -0800 Subject: [PATCH 30/46] Add more value bounds checking --- src/devices/Is31fl3730/DotMatrix.cs | 13 +++------ src/devices/Is31fl3730/DotMatrix5x7.cs | 39 +++++++++++++++++++++++--- src/devices/Is31fl3730/Is31fl3730.cs | 4 +-- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/devices/Is31fl3730/DotMatrix.cs b/src/devices/Is31fl3730/DotMatrix.cs index f8c11d0829..159b324e43 100644 --- a/src/devices/Is31fl3730/DotMatrix.cs +++ b/src/devices/Is31fl3730/DotMatrix.cs @@ -26,8 +26,8 @@ public class DotMatrix public DotMatrix(DotMatrix5x7[] matrices) { _matrices = matrices; - Width = matrices.Length * DotMatrix5x7.Width; - Height = DotMatrix5x7.Height; + Width = DotMatrix5x7.BaseWidth * matrices.Length; + Height = DotMatrix5x7.BaseHeight; } /// @@ -90,13 +90,8 @@ public void Fill(int value) throw new ArgumentException($"{nameof(y)} value ({y}) out of range."); } - int matrixIndex = x / DotMatrix5x7.Width; - int index = x % DotMatrix5x7.Width; - - if (index >= 5) - { - throw new ArgumentException($"{nameof(x)} value ({x}) out of range."); - } + int matrixIndex = x / DotMatrix5x7.BaseWidth; + int index = x % DotMatrix5x7.BaseWidth; return (matrixIndex, index); } diff --git a/src/devices/Is31fl3730/DotMatrix5x7.cs b/src/devices/Is31fl3730/DotMatrix5x7.cs index 355f7274ef..62868944d0 100644 --- a/src/devices/Is31fl3730/DotMatrix5x7.cs +++ b/src/devices/Is31fl3730/DotMatrix5x7.cs @@ -27,13 +27,31 @@ public DotMatrix5x7(Is31fl3730 is31fl3730, int matrix) _matrix = matrix; } + /// + /// Width of LED matrix (x axis). + /// + public int Width { get; } = BaseWidth; + + /// + /// Height of LED matrix (y axis). + /// + public int Height { get; } = BaseHeight; + /// /// Indexer for matrix. x: 0..4; y: 0..6. /// public int this[int x, int y] { - get => _is31fl3730.Read(_matrix, x, y); - set => _is31fl3730.Write(_matrix, x, y, value); + get + { + CheckDimensions(x, y); + return _is31fl3730.Read(_matrix, x, y); + } + set + { + CheckDimensions(x, y); + _is31fl3730.Write(_matrix, x, y, value); + } } /// @@ -49,11 +67,24 @@ public DotMatrix5x7(Is31fl3730 is31fl3730, int matrix) /// /// Width of LED matrix (x axis). /// - public static readonly int Width = 5; + public static readonly int BaseWidth = 5; /// /// Height of LED matrix (y axis). /// - public static readonly int Height = 7; + public static readonly int BaseHeight = 7; + + private static void CheckDimensions(int x, int y) + { + if (x is < 0 or >= 5) + { + throw new ArgumentException($"{nameof(x)} ({x}) is out of range."); + } + + if (y is < 0 or >= 7) + { + throw new ArgumentException($"{nameof(y)} ({y}) is out of range."); + } + } } } diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 986baaa833..dc8e0280ba 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -237,8 +237,8 @@ x x */ if (matrix > 1 || - x >= DotMatrix5x7.Width || - y >= DotMatrix5x7.Height) + x >= DotMatrix5x7.BaseWidth || + y >= DotMatrix5x7.BaseHeight) { throw new ArgumentException("Argument out of range."); } From 4ef5b67dad33cc767c8e84653911a14d1d7e286d Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 19 Dec 2022 19:55:05 -0800 Subject: [PATCH 31/46] Update bounds checking --- src/devices/Is31fl3730/DotMatrix.cs | 7 ++--- src/devices/Is31fl3730/DotMatrix5x7.cs | 25 ++--------------- src/devices/Is31fl3730/Is31fl3730.cs | 38 +++++++++++++++++++------- 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/src/devices/Is31fl3730/DotMatrix.cs b/src/devices/Is31fl3730/DotMatrix.cs index 159b324e43..e284ccd712 100644 --- a/src/devices/Is31fl3730/DotMatrix.cs +++ b/src/devices/Is31fl3730/DotMatrix.cs @@ -27,7 +27,6 @@ public DotMatrix(DotMatrix5x7[] matrices) { _matrices = matrices; Width = DotMatrix5x7.BaseWidth * matrices.Length; - Height = DotMatrix5x7.BaseHeight; } /// @@ -38,7 +37,7 @@ public DotMatrix(DotMatrix5x7[] matrices) /// /// Height of LED matrix (y axis). /// - public int Height { get; } + public int Height { get; } = DotMatrix5x7.BaseHeight; /// /// Indexer for matrices. @@ -80,12 +79,12 @@ public void Fill(int value) private (int MatrixIndex, int Index) GetMatrixIndex(int x, int y) { - if (x >= Width || x < 0) + if (x < 0 || x >= Width) { throw new ArgumentException($"{nameof(x)} value ({x}) out of range."); } - if (y >= Height || y < 0) + if (y < 0 || y >= Height) { throw new ArgumentException($"{nameof(y)} value ({y}) out of range."); } diff --git a/src/devices/Is31fl3730/DotMatrix5x7.cs b/src/devices/Is31fl3730/DotMatrix5x7.cs index 62868944d0..d40297a351 100644 --- a/src/devices/Is31fl3730/DotMatrix5x7.cs +++ b/src/devices/Is31fl3730/DotMatrix5x7.cs @@ -42,16 +42,8 @@ public DotMatrix5x7(Is31fl3730 is31fl3730, int matrix) /// public int this[int x, int y] { - get - { - CheckDimensions(x, y); - return _is31fl3730.Read(_matrix, x, y); - } - set - { - CheckDimensions(x, y); - _is31fl3730.Write(_matrix, x, y, value); - } + get => _is31fl3730.Read(_matrix, x, y); + set => _is31fl3730.Write(_matrix, x, y, value); } /// @@ -73,18 +65,5 @@ public DotMatrix5x7(Is31fl3730 is31fl3730, int matrix) /// Height of LED matrix (y axis). /// public static readonly int BaseHeight = 7; - - private static void CheckDimensions(int x, int y) - { - if (x is < 0 or >= 5) - { - throw new ArgumentException($"{nameof(x)} ({x}) is out of range."); - } - - if (y is < 0 or >= 7) - { - throw new ArgumentException($"{nameof(y)} ({y}) is out of range."); - } - } } } diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index dc8e0280ba..7fc58e9580 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -236,13 +236,7 @@ x x concern. It has nothing to do with byte structure. */ - if (matrix > 1 || - x >= DotMatrix5x7.BaseWidth || - y >= DotMatrix5x7.BaseHeight) - { - throw new ArgumentException("Argument out of range."); - } - + CheckDimensions(matrix, x, y); int logicalRow = matrix is 0 ? y : x; int logicalColumn = matrix is 0 ? x : y; byte mask = (byte)(1 << logicalColumn); @@ -260,6 +254,7 @@ x x /// The y dimension for the LED. public int Read(int matrix, int x, int y) { + CheckDimensions(matrix, x, y); int row = matrix is 0 ? y : x; int column = matrix is 0 ? x : y; int mask = 1 << column; @@ -273,6 +268,7 @@ public int Read(int matrix, int x, int y) /// public void WriteDecimalPoint(int matrix, int value) { + CheckMatrixIndex(matrix); byte[] buffer = _buffers[matrix]; int row = matrix is 0 ? MatrixValues.MatrixOneDecimalRow : MatrixValues.MatrixTwoDecimalRow; byte mask = matrix is 0 ? MatrixValues.MatrixOneDecimalMask : MatrixValues.MatrixTwoDecimalMask; @@ -285,6 +281,7 @@ public void WriteDecimalPoint(int matrix, int value) /// public void Fill(int matrix, int value) { + CheckMatrixIndex(matrix); _buffers[matrix].AsSpan().Fill((byte)value); AutoFlush(matrix); } @@ -308,6 +305,8 @@ public void Fill(int value) /// public void Flush(int matrix) { + CheckMatrixIndex(matrix); + if (_enabled[matrix]) { Write(_matrix_addresses[matrix], _buffers[matrix]); @@ -393,12 +392,31 @@ private void AutoFlush(int matrix) private DotMatrix5x7 GetMatrix(int index) { - if (index is < 0 or > 1) + CheckMatrixIndex(index); + return new DotMatrix5x7(this, index); + } + + private void CheckDimensions(int matrix, int x, int y) + { + CheckMatrixIndex(matrix); + + if (x < 0 || x >= DotMatrix5x7.BaseWidth) { - throw new ArgumentException($"{nameof(index)} ({index}) is out of range."); + throw new ArgumentException($"{nameof(x)} ({x}) value out of range."); } - return new DotMatrix5x7(this, index); + if (y < 0 || y >= DotMatrix5x7.BaseHeight) + { + throw new ArgumentException($"{nameof(y)} ({y}) value out of range."); + } + } + + private void CheckMatrixIndex(int index) + { + if (index is < 0 or > 1) + { + throw new ArgumentException($"{nameof(index)} ({index}) value out of range."); + } } } } From 6a34bc0b67eca46cdfb857a132a0d9db2eade025 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 19 Dec 2022 20:14:15 -0800 Subject: [PATCH 32/46] Add IMatrix interface --- src/devices/Display/Display.csproj | 1 + src/devices/Display/IMatrix.cs | 33 ++++++++++++++++++++++++ src/devices/Is31fl3730/DotMatrix.cs | 22 ++++------------ src/devices/Is31fl3730/DotMatrix5x7.cs | 18 ++++--------- src/devices/Is31fl3730/Is31fl3730.csproj | 3 +++ 5 files changed, 47 insertions(+), 30 deletions(-) create mode 100644 src/devices/Display/IMatrix.cs diff --git a/src/devices/Display/Display.csproj b/src/devices/Display/Display.csproj index 549ca7a5f9..40b01d13ab 100644 --- a/src/devices/Display/Display.csproj +++ b/src/devices/Display/Display.csproj @@ -15,6 +15,7 @@ + diff --git a/src/devices/Display/IMatrix.cs b/src/devices/Display/IMatrix.cs new file mode 100644 index 0000000000..cec3bf2d4c --- /dev/null +++ b/src/devices/Display/IMatrix.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Iot.Device.Display +{ + /// + /// Interface for basic LED matrix functionality. + /// + public interface IMatrix + { + /// + /// Width (x-axis) of LED matrix. + /// + int Width { get; } + + /// + /// Height (y-axis) of LED matrix. + /// + int Height { get; } + + /// + /// Indexer for matrix. + /// + int this[int x, int y] { get; set; } + + /// + /// Fill LEDs (0 is dark; 255 is all lit). + /// + public void Fill(int value); + } +} diff --git a/src/devices/Is31fl3730/DotMatrix.cs b/src/devices/Is31fl3730/DotMatrix.cs index e284ccd712..1f4ae6b2d0 100644 --- a/src/devices/Is31fl3730/DotMatrix.cs +++ b/src/devices/Is31fl3730/DotMatrix.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections; -using System.Collections.Generic; using System.Device.I2c; -using System.Threading; namespace Iot.Device.Display { @@ -15,7 +12,7 @@ namespace Iot.Device.Display // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat - public class DotMatrix + public class DotMatrix : IMatrix { private readonly DotMatrix5x7[] _matrices; @@ -29,14 +26,10 @@ public DotMatrix(DotMatrix5x7[] matrices) Width = DotMatrix5x7.BaseWidth * matrices.Length; } - /// - /// Width of LED matrix (x axis). - /// + /// public int Width { get; } - /// - /// Height of LED matrix (y axis). - /// + /// public int Height { get; } = DotMatrix5x7.BaseHeight; /// @@ -49,9 +42,7 @@ public DotMatrix(DotMatrix5x7[] matrices) /// public int Length => _matrices.Length; - /// - /// Indexer for matrix pair. - /// + /// public int this[int x, int y] { get @@ -66,9 +57,7 @@ public DotMatrix(DotMatrix5x7[] matrices) } } - /// - /// Fill All LEDs. - /// + /// public void Fill(int value) { foreach (DotMatrix5x7 matrix in _matrices) @@ -91,7 +80,6 @@ public void Fill(int value) int matrixIndex = x / DotMatrix5x7.BaseWidth; int index = x % DotMatrix5x7.BaseWidth; - return (matrixIndex, index); } diff --git a/src/devices/Is31fl3730/DotMatrix5x7.cs b/src/devices/Is31fl3730/DotMatrix5x7.cs index d40297a351..e5df1af729 100644 --- a/src/devices/Is31fl3730/DotMatrix5x7.cs +++ b/src/devices/Is31fl3730/DotMatrix5x7.cs @@ -11,7 +11,7 @@ namespace Iot.Device.Display /// /// Represents LED Dot Matrix driven by IS31FL3730. /// - public class DotMatrix5x7 + public class DotMatrix5x7 : IMatrix { private readonly Is31fl3730 _is31fl3730; private readonly int _matrix; @@ -27,28 +27,20 @@ public DotMatrix5x7(Is31fl3730 is31fl3730, int matrix) _matrix = matrix; } - /// - /// Width of LED matrix (x axis). - /// + /// public int Width { get; } = BaseWidth; - /// - /// Height of LED matrix (y axis). - /// + /// public int Height { get; } = BaseHeight; - /// - /// Indexer for matrix. x: 0..4; y: 0..6. - /// + /// public int this[int x, int y] { get => _is31fl3730.Read(_matrix, x, y); set => _is31fl3730.Write(_matrix, x, y, value); } - /// - /// Fill matrix (0 is dark; 1 is lit). - /// + /// public void Fill(int value) => _is31fl3730.Fill(_matrix, value); /// diff --git a/src/devices/Is31fl3730/Is31fl3730.csproj b/src/devices/Is31fl3730/Is31fl3730.csproj index 69e12ef66e..6a6835772b 100644 --- a/src/devices/Is31fl3730/Is31fl3730.csproj +++ b/src/devices/Is31fl3730/Is31fl3730.csproj @@ -17,5 +17,8 @@ + + + \ No newline at end of file From 18a685b5e59eaed1a9556dc24515caf455110334 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 19 Dec 2022 20:18:23 -0800 Subject: [PATCH 33/46] Fix markdown error --- src/devices/Is31fl3730/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices/Is31fl3730/README.md b/src/devices/Is31fl3730/README.md index ea64a8f109..af0408aa26 100644 --- a/src/devices/Is31fl3730/README.md +++ b/src/devices/Is31fl3730/README.md @@ -14,7 +14,6 @@ The [Micro Dot pHat](https://shop.pimoroni.com/products/microdot-phat) is an una The following code demonstrates how to control the Micro Dot pHAT. - ```csharp using I2cDevice first = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[0])); using I2cDevice second = I2cDevice.Create(new I2cConnectionSettings(busId: 1, MicroDotPhat30x7.Addresses[1])); From c2c6916a497bf48246a3fbfc6773222b6c25351e Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 19 Dec 2022 21:01:47 -0800 Subject: [PATCH 34/46] Update fill value --- src/devices/Is31fl3730/Is31fl3730.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 7fc58e9580..7381db0677 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -282,7 +282,8 @@ public void WriteDecimalPoint(int matrix, int value) public void Fill(int matrix, int value) { CheckMatrixIndex(matrix); - _buffers[matrix].AsSpan().Fill((byte)value); + int fillValue = value > 0 ? 255 : 0; + _buffers[matrix].AsSpan().Fill((byte)fillValue); AutoFlush(matrix); } From b151d50c7eb231ded10967fd679e5dfed06d057e Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Tue, 20 Dec 2022 14:30:53 -0800 Subject: [PATCH 35/46] Update README --- src/devices/Is31fl3730/DotMatrix.cs | 2 +- src/devices/Is31fl3730/DotMatrix10x7.cs | 2 +- src/devices/Is31fl3730/MicroDotPhat30x7.cs | 2 +- src/devices/Is31fl3730/README.md | 51 ++++++++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/devices/Is31fl3730/DotMatrix.cs b/src/devices/Is31fl3730/DotMatrix.cs index 1f4ae6b2d0..c1e09540ab 100644 --- a/src/devices/Is31fl3730/DotMatrix.cs +++ b/src/devices/Is31fl3730/DotMatrix.cs @@ -86,7 +86,7 @@ public void Fill(int value) /// /// Default Is31fl3730 initialization /// - public static Is31fl3730 Initialize(I2cDevice i2cDevice) + public static Is31fl3730 InitializeI2c(I2cDevice i2cDevice) { i2cDevice = i2cDevice ?? throw new ArgumentException($"{nameof(i2cDevice)} is null."); Is31fl3730 is31fl3730 = new(i2cDevice); diff --git a/src/devices/Is31fl3730/DotMatrix10x7.cs b/src/devices/Is31fl3730/DotMatrix10x7.cs index 65bb7b7d04..f6f7eeffa2 100644 --- a/src/devices/Is31fl3730/DotMatrix10x7.cs +++ b/src/devices/Is31fl3730/DotMatrix10x7.cs @@ -22,7 +22,7 @@ public class DotMatrix10x7 : DotMatrix /// /// The to create with. public DotMatrix10x7(I2cDevice i2cDevice) - : this(DotMatrix.Initialize(i2cDevice)) + : this(DotMatrix.InitializeI2c(i2cDevice)) { } diff --git a/src/devices/Is31fl3730/MicroDotPhat30x7.cs b/src/devices/Is31fl3730/MicroDotPhat30x7.cs index d18fc797fe..925633b6b1 100644 --- a/src/devices/Is31fl3730/MicroDotPhat30x7.cs +++ b/src/devices/Is31fl3730/MicroDotPhat30x7.cs @@ -26,7 +26,7 @@ public class MicroDotPhat30x7 : DotMatrix /// The first Dot Matrix pair. /// The first Dot Matrix pair. public MicroDotPhat30x7(I2cDevice first, I2cDevice second, I2cDevice third) - : this(DotMatrix.Initialize(first), DotMatrix.Initialize(second), DotMatrix.Initialize(third)) + : this(DotMatrix.InitializeI2c(first), DotMatrix.InitializeI2c(second), DotMatrix.InitializeI2c(third)) { } diff --git a/src/devices/Is31fl3730/README.md b/src/devices/Is31fl3730/README.md index af0408aa26..dd74632658 100644 --- a/src/devices/Is31fl3730/README.md +++ b/src/devices/Is31fl3730/README.md @@ -57,3 +57,54 @@ Thread.Sleep(1000); matrix.Fill(0); ``` + +## Multiple LED Breakout Units + +The [LED Dot Matrix Breakout](https://shop.pimoroni.com/products/led-dot-matrix-breakout) includes two matrices and supports using up to three of the breakouts together giving you six matrices to drive. It's straightforward to tie them all together into a single logical matrix. You can do with that with the [`DotMatrix`](DotMatrix.cs) class, as demonstrated in the following sample. Alternatively, you can use [`MicroDotPhat30x7`](MicroDotPhat30x7.cs) class if you have three breakouts and follow the same ordering of I2C addresses. + + + +```csharp +using I2cDevice firstI2c = I2cDevice.Create(new I2cConnectionSettings(busId: 1, 0x61)); +using I2cDevice secondI2c = I2cDevice.Create(new I2cConnectionSettings(busId: 1, 0x62)); +using I2cDevice thirdI2c = I2cDevice.Create(new I2cConnectionSettings(busId: 1, 0x63)); + +Is31fl3730 first = DotMatrix.InitializeI2c(firstI2c); +Is31fl3730 second = DotMatrix.InitializeI2c(secondI2c); +Is31fl3730 third = DotMatrix.InitializeI2c(thirdI2c); + +DotMatrix5x7[] matrices = new DotMatrix5x7[] +{ + first[1], + first[0], + second[1], + second[0], + third[1], + third[0], +}; + +DotMatrix matrix = new(matrices); + +matrix.Fill(0); + +matrix[0, 0] = 1; +matrix[0, 6] = 1; +matrix[29, 0] = 1; +matrix[29, 6] = 1; +Thread.Sleep(500); + +matrix.Fill(255); +Thread.Sleep(1000); + +matrix.Fill(0); +``` + +> The default I2C address is 0x61. You can change this to 0x63 by cutting the trace on the back of the breakout. If you cut the trace and solder the bridge the address will be 0x62 - so it's possible to use up to three of these breakouts at the same time. + +That's from the [LED Dot Matrix Breakout](https://shop.pimoroni.com/products/led-dot-matrix-breakout) product page. + +Said slightly differently: + +- The default address is `0x61` +- Cut the bridge of `ADDR2` to change the I2C address to `0x63` +- Cut the bridge of `ADDR2` and bridge the two pads of `ADDR1` (with solder) to change the I2C address to `0x62`. From 5fad1d5609c9765c0b3ad5d0dfff0c095391e314 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 11 Jan 2023 20:53:32 -0800 Subject: [PATCH 36/46] Add solution file --- src/devices/Is31fl3730/Is31fl3730.cs | 2 +- src/devices/Is31fl3730/Is31fl3730.sln | 28 +++++++++++++++++++ src/devices/Is31fl3730/README.md | 2 +- .../{Matrix.samples.csproj => Matrix.csproj} | 0 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 src/devices/Is31fl3730/Is31fl3730.sln rename src/devices/Is31fl3730/samples/{Matrix.samples.csproj => Matrix.csproj} (100%) diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 7381db0677..07745f8ffe 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -34,7 +34,7 @@ public class Is31fl3730 /// The to create with. public Is31fl3730(I2cDevice i2cDevice) { - _i2cDevice = i2cDevice ?? throw new ArgumentException($"{nameof(i2cDevice)} is null."); + _i2cDevice = i2cDevice ?? throw new ArgumentNullException(nameof(i2cDevice)); } /* diff --git a/src/devices/Is31fl3730/Is31fl3730.sln b/src/devices/Is31fl3730/Is31fl3730.sln new file mode 100644 index 0000000000..8548f66fa2 --- /dev/null +++ b/src/devices/Is31fl3730/Is31fl3730.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Is31fl3730", "Is31fl3730.csproj", "{0FBEF62C-789D-4B37-8950-5A32EC6F0E64}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix", "samples\Matrix.csproj", "{1BECA2AF-613D-4A95-888B-76A5B3233BCD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0FBEF62C-789D-4B37-8950-5A32EC6F0E64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0FBEF62C-789D-4B37-8950-5A32EC6F0E64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0FBEF62C-789D-4B37-8950-5A32EC6F0E64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0FBEF62C-789D-4B37-8950-5A32EC6F0E64}.Release|Any CPU.Build.0 = Release|Any CPU + {1BECA2AF-613D-4A95-888B-76A5B3233BCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1BECA2AF-613D-4A95-888B-76A5B3233BCD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1BECA2AF-613D-4A95-888B-76A5B3233BCD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1BECA2AF-613D-4A95-888B-76A5B3233BCD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/devices/Is31fl3730/README.md b/src/devices/Is31fl3730/README.md index dd74632658..5ed7fb0f98 100644 --- a/src/devices/Is31fl3730/README.md +++ b/src/devices/Is31fl3730/README.md @@ -2,7 +2,7 @@ The [IS31FL3730](https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf) is a compact LED driver that can drive one or two 8×8, 7×9, 6×10, or 5×11 dot matrix displays. The device can be programmed via an I2C compatible interface. -This binding is similar to the Python version in [pimoroni/microdot-phat](https://github.com/pimoroni/microdot-phat). +This binding is similar to [pimoroni/microdot-phat](https://github.com/pimoroni/microdot-phat), a Python implementation provided by Pimoroni. It is demonstrated in [samples/Program.cs](samples/Program.cs). diff --git a/src/devices/Is31fl3730/samples/Matrix.samples.csproj b/src/devices/Is31fl3730/samples/Matrix.csproj similarity index 100% rename from src/devices/Is31fl3730/samples/Matrix.samples.csproj rename to src/devices/Is31fl3730/samples/Matrix.csproj From ecab9e3eee1966c09cfeb11aef790a21b40d9fad Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 16 Jan 2023 14:11:53 -0800 Subject: [PATCH 37/46] Update src/devices/Is31fl3730/Current.cs Co-authored-by: Laurent Ellerbach --- src/devices/Is31fl3730/Current.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/Is31fl3730/Current.cs b/src/devices/Is31fl3730/Current.cs index 122f7da9ad..e10c848852 100644 --- a/src/devices/Is31fl3730/Current.cs +++ b/src/devices/Is31fl3730/Current.cs @@ -38,7 +38,7 @@ public enum Current /// /// 45 mA /// - CMA45 = 0b0001, + CmA45 = 0b0001, /// /// 75 mA From bf10f227f506245b4ec9dddabadd042dce895d19 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 16 Jan 2023 13:34:04 -0800 Subject: [PATCH 38/46] Update per feedback --- .../Is31fl3730/ConfigurationRegister.cs | 16 +++++++++++ src/devices/Is31fl3730/Current.cs | 9 +------ src/devices/Is31fl3730/DisplayMode.cs | 9 +------ src/devices/Is31fl3730/DotMatrix.cs | 2 +- src/devices/Is31fl3730/DotMatrix10x7.cs | 5 +--- .../{Registers.cs => FunctionRegister.cs} | 27 ++++++------------- src/devices/Is31fl3730/Is31fl3730.cs | 4 +-- src/devices/Is31fl3730/Is31fl3730.csproj | 3 ++- src/devices/Is31fl3730/MatrixMode.cs | 2 +- src/devices/Is31fl3730/MatrixValues.cs | 14 +++++----- 10 files changed, 40 insertions(+), 51 deletions(-) create mode 100644 src/devices/Is31fl3730/ConfigurationRegister.cs rename src/devices/Is31fl3730/{Registers.cs => FunctionRegister.cs} (59%) diff --git a/src/devices/Is31fl3730/ConfigurationRegister.cs b/src/devices/Is31fl3730/ConfigurationRegister.cs new file mode 100644 index 0000000000..6eb58febd1 --- /dev/null +++ b/src/devices/Is31fl3730/ConfigurationRegister.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Iot.Device.Display +{ + /// + /// Register addresses for the Configuration Register. + /// + internal static class ConfigurationRegister + { + /// + /// Shutdown value. + /// + internal static byte Shutdown = 0x80; + } +} diff --git a/src/devices/Is31fl3730/Current.cs b/src/devices/Is31fl3730/Current.cs index e10c848852..52e1738077 100644 --- a/src/devices/Is31fl3730/Current.cs +++ b/src/devices/Is31fl3730/Current.cs @@ -1,17 +1,10 @@ // 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.Device.Spi; -using System.Threading; -using System.Threading.Tasks; -using Iot.Device.Multiplexing.Utility; - namespace Iot.Device.Display { /// - /// Represents an IS31FL3731 LED Matrix driver + /// IS31FL3730 current setting for row output. /// public enum Current { diff --git a/src/devices/Is31fl3730/DisplayMode.cs b/src/devices/Is31fl3730/DisplayMode.cs index f2a1d806ab..d90ed821d3 100644 --- a/src/devices/Is31fl3730/DisplayMode.cs +++ b/src/devices/Is31fl3730/DisplayMode.cs @@ -1,17 +1,10 @@ // 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.Device.Spi; -using System.Threading; -using System.Threading.Tasks; -using Iot.Device.Multiplexing.Utility; - namespace Iot.Device.Display { /// - /// Represents an IS31FL3731 LED Matrix driver + /// IS31FL3730 display mode, controlling which matrices are used. /// public enum DisplayMode { diff --git a/src/devices/Is31fl3730/DotMatrix.cs b/src/devices/Is31fl3730/DotMatrix.cs index c1e09540ab..861b668359 100644 --- a/src/devices/Is31fl3730/DotMatrix.cs +++ b/src/devices/Is31fl3730/DotMatrix.cs @@ -88,7 +88,7 @@ public void Fill(int value) /// public static Is31fl3730 InitializeI2c(I2cDevice i2cDevice) { - i2cDevice = i2cDevice ?? throw new ArgumentException($"{nameof(i2cDevice)} is null."); + i2cDevice = i2cDevice ?? throw new ArgumentNullException(nameof(i2cDevice)); Is31fl3730 is31fl3730 = new(i2cDevice); is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; is31fl3730.Initialize(); diff --git a/src/devices/Is31fl3730/DotMatrix10x7.cs b/src/devices/Is31fl3730/DotMatrix10x7.cs index f6f7eeffa2..701e947a7e 100644 --- a/src/devices/Is31fl3730/DotMatrix10x7.cs +++ b/src/devices/Is31fl3730/DotMatrix10x7.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections; -using System.Collections.Generic; using System.Device.I2c; -using System.Threading; namespace Iot.Device.Display { @@ -42,7 +39,7 @@ public DotMatrix10x7(Is31fl3730 is31fl3730) private static DotMatrix5x7[] Initialize(Is31fl3730 is31fl3730) { - is31fl3730 = is31fl3730 ?? throw new ArgumentException($"{nameof(is31fl3730)} is null"); + is31fl3730 = is31fl3730 ?? throw new ArgumentNullException(nameof(is31fl3730)); return new DotMatrix5x7[] { is31fl3730[1], diff --git a/src/devices/Is31fl3730/Registers.cs b/src/devices/Is31fl3730/FunctionRegister.cs similarity index 59% rename from src/devices/Is31fl3730/Registers.cs rename to src/devices/Is31fl3730/FunctionRegister.cs index 0e40030fff..f2d9f0efab 100644 --- a/src/devices/Is31fl3730/Registers.cs +++ b/src/devices/Is31fl3730/FunctionRegister.cs @@ -6,52 +6,41 @@ namespace Iot.Device.Display /// /// Register addresses for the Function Register. /// - public static class FunctionRegister + internal static class FunctionRegister { /// /// Address for Configuration Register. /// - public static byte Configuration = 0x0; + internal static byte Configuration = 0x0; /// /// Address for Matrix 1 Data Register. /// - public static byte Matrix1 = 0x01; + internal static byte Matrix1 = 0x01; /// /// Address for Update Column Register. /// - public static byte UpdateColumn = 0x0C; + internal static byte UpdateColumn = 0x0C; /// /// Address for Lighting Effect Register. /// - public static byte LightingEffect = 0x0D; + internal static byte LightingEffect = 0x0D; /// /// Address for Matrix 2 Data Register. /// - public static byte Matrix2 = 0x0E; + internal static byte Matrix2 = 0x0E; /// /// Address for PWM Register. /// - public static byte Pwm = 0x19; + internal static byte Pwm = 0x19; /// /// Address for Reset Register. /// - public static byte Reset = 0xFF; - } - - /// - /// Register addresses for the Configuration Register. - /// - public static class ConfigurationRegister - { - /// - /// Shutdown value. - /// - public static byte Shutdown = 0x80; + internal static byte Reset = 0xFF; } } diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 07745f8ffe..5a19b4f23a 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -9,7 +9,7 @@ namespace Iot.Device.Display { /// - /// Represents an IS31FL3731 LED Matrix driver + /// Represents an IS31FL3730 LED Matrix driver /// // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf // Product: https://shop.pimoroni.com/products/microdot-phat @@ -83,7 +83,7 @@ public Is31fl3730(I2cDevice i2cDevice) public DisplayMode DisplayMode { get; set; } /// - /// Enables or disables auto-buggering. + /// Enables or disables auto-buffering. /// public bool BufferingEnabled { get; set; } = true; diff --git a/src/devices/Is31fl3730/Is31fl3730.csproj b/src/devices/Is31fl3730/Is31fl3730.csproj index 6a6835772b..a52514968c 100644 --- a/src/devices/Is31fl3730/Is31fl3730.csproj +++ b/src/devices/Is31fl3730/Is31fl3730.csproj @@ -5,12 +5,13 @@ + + - diff --git a/src/devices/Is31fl3730/MatrixMode.cs b/src/devices/Is31fl3730/MatrixMode.cs index f857cde2cd..879909d11d 100644 --- a/src/devices/Is31fl3730/MatrixMode.cs +++ b/src/devices/Is31fl3730/MatrixMode.cs @@ -11,7 +11,7 @@ namespace Iot.Device.Display { /// - /// Represents an IS31FL3731 LED Matrix driver + /// IS31FL3730 matrix modes, controlling the size of the matrix. /// public enum MatrixMode { diff --git a/src/devices/Is31fl3730/MatrixValues.cs b/src/devices/Is31fl3730/MatrixValues.cs index a1b605d971..d9b9bf28ce 100644 --- a/src/devices/Is31fl3730/MatrixValues.cs +++ b/src/devices/Is31fl3730/MatrixValues.cs @@ -4,33 +4,33 @@ namespace Iot.Device.Display { /// - /// Matrix Values. + /// IS31FL3730 matrix driver values. /// - public static class MatrixValues + internal static class MatrixValues { /// /// Arbitrary 8-bit value to write to Update Column Register, as required by datasheet. /// - public static byte EightBitValue = 8; + internal static byte EightBitValue = 8; /// /// Matrix one decimal point mask. /// - public static byte MatrixOneDecimalMask = 128; + internal static byte MatrixOneDecimalMask = 128; /// /// Matrix one decimal point row. /// - public static byte MatrixOneDecimalRow = 6; + internal static byte MatrixOneDecimalRow = 6; /// /// Matrix two mask for decimal point. /// - public static byte MatrixTwoDecimalMask = 64; + internal static byte MatrixTwoDecimalMask = 64; /// /// Matrix two decimal point row. /// - public static byte MatrixTwoDecimalRow = 7; + internal static byte MatrixTwoDecimalRow = 7; } } From 939615451218e4c21e9ddb8f324d6cb5d8b38dfc Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 16 Jan 2023 14:10:37 -0800 Subject: [PATCH 39/46] Update to PinValue --- src/devices/Is31fl3730/DotMatrix.cs | 25 +++++++++++++++-------- src/devices/Is31fl3730/DotMatrix5x7.cs | 23 ++++++++++----------- src/devices/Is31fl3730/Is31fl3730.cs | 20 +++++++++--------- src/devices/Is31fl3730/samples/Program.cs | 11 +++++----- 4 files changed, 44 insertions(+), 35 deletions(-) diff --git a/src/devices/Is31fl3730/DotMatrix.cs b/src/devices/Is31fl3730/DotMatrix.cs index 861b668359..4162da6c31 100644 --- a/src/devices/Is31fl3730/DotMatrix.cs +++ b/src/devices/Is31fl3730/DotMatrix.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Device.Gpio; using System.Device.I2c; namespace Iot.Device.Display @@ -12,7 +13,7 @@ namespace Iot.Device.Display // Datasheet: https://cdn-shop.adafruit.com/product-files/3017/31FL3730.pdf // Product: https://shop.pimoroni.com/products/led-dot-matrix-breakout // Related repo: https://github.com/pimoroni/microdot-phat - public class DotMatrix : IMatrix + public class DotMatrix { private readonly DotMatrix5x7[] _matrices; @@ -26,14 +27,18 @@ public DotMatrix(DotMatrix5x7[] matrices) Width = DotMatrix5x7.BaseWidth * matrices.Length; } - /// + /// + /// Width (x-axis) of matrix. + /// public int Width { get; } - /// + /// + /// Height (y-axis) for matrix. + /// public int Height { get; } = DotMatrix5x7.BaseHeight; /// - /// Indexer for matrices. + /// Indexer for matrix. /// public DotMatrix5x7 this[int matrix] => _matrices[matrix]; @@ -42,8 +47,10 @@ public DotMatrix(DotMatrix5x7[] matrices) /// public int Length => _matrices.Length; - /// - public int this[int x, int y] + /// + /// Indexer for matrix. + /// + public PinValue this[int x, int y] { get { @@ -57,8 +64,10 @@ public DotMatrix(DotMatrix5x7[] matrices) } } - /// - public void Fill(int value) + /// + /// Fill LEDs with value. + /// + public void Fill(PinValue value) { foreach (DotMatrix5x7 matrix in _matrices) { diff --git a/src/devices/Is31fl3730/DotMatrix5x7.cs b/src/devices/Is31fl3730/DotMatrix5x7.cs index e5df1af729..f0f1d62108 100644 --- a/src/devices/Is31fl3730/DotMatrix5x7.cs +++ b/src/devices/Is31fl3730/DotMatrix5x7.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Device.Gpio; using System.Device.I2c; using System.Threading; @@ -11,7 +12,7 @@ namespace Iot.Device.Display /// /// Represents LED Dot Matrix driven by IS31FL3730. /// - public class DotMatrix5x7 : IMatrix + public class DotMatrix5x7 { private readonly Is31fl3730 _is31fl3730; private readonly int _matrix; @@ -27,26 +28,24 @@ public DotMatrix5x7(Is31fl3730 is31fl3730, int matrix) _matrix = matrix; } - /// - public int Width { get; } = BaseWidth; - - /// - public int Height { get; } = BaseHeight; - - /// - public int this[int x, int y] + /// + /// Indexer for matrix. + /// + public PinValue this[int x, int y] { get => _is31fl3730.Read(_matrix, x, y); set => _is31fl3730.Write(_matrix, x, y, value); } - /// - public void Fill(int value) => _is31fl3730.Fill(_matrix, value); + /// + /// Fill LEDs with value. + /// + public void Fill(PinValue value) => _is31fl3730.Fill(_matrix, value); /// /// Fill matrix (0 is dark; 1 is lit). /// - public void WriteDecimalPoint(int value) => _is31fl3730.WriteDecimalPoint(_matrix, value); + public void WriteDecimalPoint(PinValue value) => _is31fl3730.WriteDecimalPoint(_matrix, value); /// /// Width of LED matrix (x axis). diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 5a19b4f23a..ccef17f00f 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Device.Gpio; using System.Device.I2c; using static System.Linq.Enumerable; @@ -141,7 +142,7 @@ public void Initialize() /// The x dimension for the LED. /// The y dimension for the LED. /// The value to write. - public void Write(int matrix, int x, int y, int value) + public void Write(int matrix, int x, int y, PinValue value) { /* The following diagrams and information demonstrate how the matrix is structured. @@ -241,7 +242,7 @@ x x int logicalColumn = matrix is 0 ? x : y; byte mask = (byte)(1 << logicalColumn); byte[] buffer = _buffers[matrix]; - buffer[logicalRow] = UpdateByte(buffer[logicalRow], mask, value); + buffer[logicalRow] = UpdateByte(buffer[logicalRow], mask, (int)value); AutoFlush(matrix); } @@ -252,7 +253,7 @@ x x /// The matrix to use. /// The x dimension for the LED. /// The y dimension for the LED. - public int Read(int matrix, int x, int y) + public PinValue Read(int matrix, int x, int y) { CheckDimensions(matrix, x, y); int row = matrix is 0 ? y : x; @@ -266,7 +267,7 @@ public int Read(int matrix, int x, int y) /// /// Update decimal point for matrix. /// - public void WriteDecimalPoint(int matrix, int value) + public void WriteDecimalPoint(int matrix, PinValue value) { CheckMatrixIndex(matrix); byte[] buffer = _buffers[matrix]; @@ -279,18 +280,17 @@ public void WriteDecimalPoint(int matrix, int value) /// /// Fill LEDs with value, per matrix. /// - public void Fill(int matrix, int value) + public void Fill(int matrix, PinValue value) { CheckMatrixIndex(matrix); - int fillValue = value > 0 ? 255 : 0; - _buffers[matrix].AsSpan().Fill((byte)fillValue); + _buffers[matrix].AsSpan().Fill((byte)value); AutoFlush(matrix); } /// /// Fill LEDs with value. /// - public void Fill(int value) + public void Fill(PinValue value) { foreach (int index in Range(0, 2)) { @@ -360,9 +360,9 @@ private void Write(byte address, ReadOnlySpan value) private void Write(byte address, byte value) => _i2cDevice.Write(stackalloc byte[] { address, value }); - private byte UpdateByte(byte data, byte mask, int value) + private byte UpdateByte(byte data, byte mask, PinValue value) { - if (value is 1) + if (value == PinValue.High) { data |= mask; } diff --git a/src/devices/Is31fl3730/samples/Program.cs b/src/devices/Is31fl3730/samples/Program.cs index 6bcd05b5f5..27110cf96e 100644 --- a/src/devices/Is31fl3730/samples/Program.cs +++ b/src/devices/Is31fl3730/samples/Program.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Device.Gpio; using System.Device.I2c; using System.Linq; using System.Threading; @@ -31,7 +32,7 @@ matrix[width, height] = 1; Thread.Sleep(500); -matrix.Fill(255); +matrix.Fill(1); Thread.Sleep(1000); matrix.Fill(0); @@ -124,20 +125,20 @@ Thread.Sleep(500); matrix.Fill(0); -void WriteRowPixels(int row, IEnumerable pixels, int value) +void WriteRowPixels(int row, IEnumerable pixels, PinValue value) { foreach (int pixel in pixels) { - matrix[pixel, row] = (byte)value; + matrix[pixel, row] = value; Thread.Sleep(15); } } -void WriteColumnPixels(int column, IEnumerable pixels, int value) +void WriteColumnPixels(int column, IEnumerable pixels, PinValue value) { foreach (int pixel in pixels) { - matrix[column, pixel] = (byte)value; + matrix[column, pixel] = value; Thread.Sleep(15); } } From de781f687af070385239ad05e25de087d4aabb5e Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 16 Jan 2023 15:34:11 -0800 Subject: [PATCH 40/46] Update per feedback --- src/devices/Is31fl3730/Current.cs | 14 +-- src/devices/Is31fl3730/DisplayMode.cs | 4 +- src/devices/Is31fl3730/DotMatrix.cs | 3 +- src/devices/Is31fl3730/Is31fl3730.cs | 105 ++++++------------ src/devices/Is31fl3730/Is31fl3730.csproj | 2 +- ...nfigurationRegister.cs => ShutdownMode.cs} | 13 ++- 6 files changed, 52 insertions(+), 89 deletions(-) rename src/devices/Is31fl3730/{ConfigurationRegister.cs => ShutdownMode.cs} (54%) diff --git a/src/devices/Is31fl3730/Current.cs b/src/devices/Is31fl3730/Current.cs index 52e1738077..1221dae0ef 100644 --- a/src/devices/Is31fl3730/Current.cs +++ b/src/devices/Is31fl3730/Current.cs @@ -9,32 +9,32 @@ namespace Iot.Device.Display public enum Current { /// - /// 5 mA + /// 5 mA. /// CmA5 = 0b1000, /// - /// 10 mA + /// 10 mA. /// CmA10 = 0b1001, /// - /// 35 mA + /// 35 mA. /// CmA35 = 0b1110, /// - /// 40 mA + /// 40 mA (default). /// - CmA40 = 0b0, + CmA40 = 0b0000, /// - /// 45 mA + /// 45 mA. /// CmA45 = 0b0001, /// - /// 75 mA + /// 75 mA. /// CmA75 = 0b0111, } diff --git a/src/devices/Is31fl3730/DisplayMode.cs b/src/devices/Is31fl3730/DisplayMode.cs index d90ed821d3..b8468cad09 100644 --- a/src/devices/Is31fl3730/DisplayMode.cs +++ b/src/devices/Is31fl3730/DisplayMode.cs @@ -11,12 +11,12 @@ public enum DisplayMode /// /// Enable matrix one only. /// - MatrixOneOnly = 0x0, + MatrixOneOnly = 0x00, /// /// Enable matrix two only. /// - MatrixTwoOnly = 0x8, + MatrixTwoOnly = 0x08, /// /// Enable matrix one and two. diff --git a/src/devices/Is31fl3730/DotMatrix.cs b/src/devices/Is31fl3730/DotMatrix.cs index 4162da6c31..5b4c5bc51f 100644 --- a/src/devices/Is31fl3730/DotMatrix.cs +++ b/src/devices/Is31fl3730/DotMatrix.cs @@ -99,8 +99,7 @@ public static Is31fl3730 InitializeI2c(I2cDevice i2cDevice) { i2cDevice = i2cDevice ?? throw new ArgumentNullException(nameof(i2cDevice)); Is31fl3730 is31fl3730 = new(i2cDevice); - is31fl3730.DisplayMode = DisplayMode.MatrixOneAndTwo; - is31fl3730.Initialize(); + is31fl3730.UpdateConfiguration(ShowdownMode.Normal, MatrixMode.Size8x8, DisplayMode.MatrixOneAndTwo); return is31fl3730; } } diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index ccef17f00f..03b7806309 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -27,7 +27,6 @@ public class Is31fl3730 }; private readonly bool[] _enabled = new bool[2]; private I2cDevice _i2cDevice; - private int _configurationValue = 0; /// /// Initialize IS31FL3730 device @@ -64,77 +63,63 @@ public Is31fl3730(I2cDevice i2cDevice) public const int DefaultI2cAddress = 0x61; /// - /// Brightness of LED matrix (override default value (128; max brightness); set before calling Initialize method). - /// - public int Brightness { get; set; } - - /// - /// Full current setting for each row output of LED matrix (override default value (40 mA)); set before calling Initialize method). + /// Enables or disables auto-buffering. /// - public Current Current { get; set; } + public bool BufferingEnabled { get; set; } = true; /// - /// Matrix mode (override default value (8x8); set before calling Initialize method). + /// Indexer for matrices. /// - public MatrixMode MatrixMode { get; set; } + public DotMatrix5x7 this[int index] => GetMatrix(index); /// - /// Display mode (use to override default value (Matrix 1 only; right-most); set before calling Initialize method). + /// Update bright of LED matrix for each of 128 items. /// - public DisplayMode DisplayMode { get; set; } + // From datasheet: + // Set high bit for the 128th item + // Set high bit low for the remaining 127 items + // And then set lower bits as appropriate, to represent 0-127 + public void UpdateBrightness(byte value) => Write(FunctionRegister.Pwm, value); /// - /// Enables or disables auto-buffering. + /// Update current setting for each row output of LED matrix (default value is 40 mA). /// - public bool BufferingEnabled { get; set; } = true; + public void UpdateCurrent(Current value) => Write(FunctionRegister.LightingEffect, (byte)value); /// - /// Indexer for matrices. + /// Update configuration register, which controls shutdown, matrix, and display modes. /// - public DotMatrix5x7 this[int index] => GetMatrix(index); - - /// - /// Initialize LED driver. - /// - public void Initialize() + public void UpdateConfiguration(ShowdownMode shutdown, MatrixMode matrix, DisplayMode display) { - // Set size of matrix - if (MatrixMode > 0) - { - _configurationValue |= (int)MatrixMode; - } + byte configuration = 0; + configuration |= (byte)shutdown; + configuration |= (byte)matrix; + configuration |= (byte)display; + Write(FunctionRegister.Configuration, configuration); // Set number of and which supported matrices (either or both) - if (DisplayMode > 0) - { - _enabled[0] = DisplayMode is DisplayMode.MatrixOneOnly or DisplayMode.MatrixOneAndTwo; - _enabled[1] = DisplayMode is DisplayMode.MatrixTwoOnly or DisplayMode.MatrixOneAndTwo; - _configurationValue |= (int)DisplayMode; - } - else + if (display is DisplayMode.MatrixOneOnly) { _enabled[0] = true; + _enabled[1] = false; } - - // If (non-default) configurations values are set, write to device - if (_configurationValue > 0) - { - Write(FunctionRegister.Configuration, (byte)_configurationValue); - } - - // Set current value - if (Current > 0) + else if (display is DisplayMode.MatrixTwoOnly) { - Write(FunctionRegister.LightingEffect, (byte)Current); + _enabled[0] = false; + _enabled[1] = true; } - - // Set brightness value - if (Brightness > 0) + else { - Write(FunctionRegister.Pwm, (byte)Brightness); + _enabled[0] = true; + _enabled[1] = true; } } + /// + /// Resets all registers to default value. + /// + public void ResetRegisters() => Write(FunctionRegister.Reset, MatrixValues.EightBitValue); + /// /// Write LED for matrix. /// @@ -324,32 +309,6 @@ public void Flush() Flush(1); } - /// - /// Resets all registers to default value. - /// - public void Reset() => Write(FunctionRegister.Reset, MatrixValues.EightBitValue); - - /// - /// Set the shutdown mode. - /// - /// Set the showdown mode. `true` sets device into shutdown mode. `false` sets device into normal operation. - public void Shutdown(bool shutdown) - { - // mode values - // 0 = normal operation - // 1 = shutdown mode - if (shutdown) - { - _configurationValue |= ConfigurationRegister.Shutdown; - } - else - { - _configurationValue &= ~ConfigurationRegister.Shutdown; - } - - WriteUpdateRegister(); - } - private void Write(byte address, ReadOnlySpan value) { Span data = stackalloc byte[value.Length + 1]; diff --git a/src/devices/Is31fl3730/Is31fl3730.csproj b/src/devices/Is31fl3730/Is31fl3730.csproj index a52514968c..ea6789372f 100644 --- a/src/devices/Is31fl3730/Is31fl3730.csproj +++ b/src/devices/Is31fl3730/Is31fl3730.csproj @@ -5,13 +5,13 @@ - + diff --git a/src/devices/Is31fl3730/ConfigurationRegister.cs b/src/devices/Is31fl3730/ShutdownMode.cs similarity index 54% rename from src/devices/Is31fl3730/ConfigurationRegister.cs rename to src/devices/Is31fl3730/ShutdownMode.cs index 6eb58febd1..3308f1a8e7 100644 --- a/src/devices/Is31fl3730/ConfigurationRegister.cs +++ b/src/devices/Is31fl3730/ShutdownMode.cs @@ -4,13 +4,18 @@ namespace Iot.Device.Display { /// - /// Register addresses for the Configuration Register. + /// IS31FL3730 shutdown mode. /// - internal static class ConfigurationRegister + public enum ShowdownMode { /// - /// Shutdown value. + /// Enable normal operation. /// - internal static byte Shutdown = 0x80; + Normal = 0x00, + + /// + /// Enable shutdown mode. + /// + Shutdown = 0x80, } } From 0001fab4c669026b8a7d7ef4d5fb315f683c2b79 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 16 Jan 2023 15:38:56 -0800 Subject: [PATCH 41/46] Update per feedback --- src/devices/Is31fl3730/DotMatrix.cs | 3 ++- src/devices/Is31fl3730/Is31fl3730.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/devices/Is31fl3730/DotMatrix.cs b/src/devices/Is31fl3730/DotMatrix.cs index 5b4c5bc51f..4726e6351f 100644 --- a/src/devices/Is31fl3730/DotMatrix.cs +++ b/src/devices/Is31fl3730/DotMatrix.cs @@ -20,7 +20,7 @@ public class DotMatrix /// /// Initialize virtual Dot Matrix. /// - /// The to create with. + /// The matrices to use. public DotMatrix(DotMatrix5x7[] matrices) { _matrices = matrices; @@ -57,6 +57,7 @@ public DotMatrix(DotMatrix5x7[] matrices) var (matrixIndex, index) = GetMatrixIndex(x, y); return _matrices[matrixIndex][index, y]; } + set { var (matrixIndex, index) = GetMatrixIndex(x, y); diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 03b7806309..ac0877c00c 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -29,7 +29,7 @@ public class Is31fl3730 private I2cDevice _i2cDevice; /// - /// Initialize IS31FL3730 device + /// Initialize IS31FL3730 device. /// /// The to create with. public Is31fl3730(I2cDevice i2cDevice) From d0d0964d4b2d676b91cff67fb18690efa589eb60 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 16 Jan 2023 15:43:54 -0800 Subject: [PATCH 42/46] Remove IMatrix interface --- src/devices/Display/Display.csproj | 1 - src/devices/Display/IMatrix.cs | 33 ------------------------ src/devices/Is31fl3730/Is31fl3730.csproj | 3 --- 3 files changed, 37 deletions(-) delete mode 100644 src/devices/Display/IMatrix.cs diff --git a/src/devices/Display/Display.csproj b/src/devices/Display/Display.csproj index 40b01d13ab..549ca7a5f9 100644 --- a/src/devices/Display/Display.csproj +++ b/src/devices/Display/Display.csproj @@ -15,7 +15,6 @@ - diff --git a/src/devices/Display/IMatrix.cs b/src/devices/Display/IMatrix.cs deleted file mode 100644 index cec3bf2d4c..0000000000 --- a/src/devices/Display/IMatrix.cs +++ /dev/null @@ -1,33 +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; - -namespace Iot.Device.Display -{ - /// - /// Interface for basic LED matrix functionality. - /// - public interface IMatrix - { - /// - /// Width (x-axis) of LED matrix. - /// - int Width { get; } - - /// - /// Height (y-axis) of LED matrix. - /// - int Height { get; } - - /// - /// Indexer for matrix. - /// - int this[int x, int y] { get; set; } - - /// - /// Fill LEDs (0 is dark; 255 is all lit). - /// - public void Fill(int value); - } -} diff --git a/src/devices/Is31fl3730/Is31fl3730.csproj b/src/devices/Is31fl3730/Is31fl3730.csproj index ea6789372f..6380ea41c2 100644 --- a/src/devices/Is31fl3730/Is31fl3730.csproj +++ b/src/devices/Is31fl3730/Is31fl3730.csproj @@ -18,8 +18,5 @@ - - - \ No newline at end of file From 09217241fd74149b69a283df98ec3df6ab675202 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Mon, 16 Jan 2023 20:55:41 -0800 Subject: [PATCH 43/46] Update type names --- src/devices/Is31fl3730/FunctionRegister.cs | 4 ++-- src/devices/Is31fl3730/Is31fl3730.cs | 17 +++++++++-------- src/devices/Is31fl3730/MatrixValues.cs | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/devices/Is31fl3730/FunctionRegister.cs b/src/devices/Is31fl3730/FunctionRegister.cs index f2d9f0efab..996377aff8 100644 --- a/src/devices/Is31fl3730/FunctionRegister.cs +++ b/src/devices/Is31fl3730/FunctionRegister.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Iot.Device.Display +namespace Iot.Device.Display.Internal { /// /// Register addresses for the Function Register. /// - internal static class FunctionRegister + internal static class Is31fl3730_FunctionRegister { /// /// Address for Configuration Register. diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index ac0877c00c..69c00f6e11 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Device.Gpio; using System.Device.I2c; +using Iot.Device.Display.Internal; using static System.Linq.Enumerable; namespace Iot.Device.Display @@ -19,7 +20,7 @@ namespace Iot.Device.Display // Based on: https://github.com/pimoroni/microdot-phat/blob/master/library/microdotphat/matrix.py public class Is31fl3730 { - private readonly byte[] _matrix_addresses = new byte[] { FunctionRegister.Matrix1, FunctionRegister.Matrix2 }; + private readonly byte[] _matrix_addresses = new byte[] { Is31fl3730_FunctionRegister.Matrix1, Is31fl3730_FunctionRegister.Matrix2 }; private readonly List _buffers = new List { new byte[8], @@ -79,12 +80,12 @@ public Is31fl3730(I2cDevice i2cDevice) // Set high bit for the 128th item // Set high bit low for the remaining 127 items // And then set lower bits as appropriate, to represent 0-127 - public void UpdateBrightness(byte value) => Write(FunctionRegister.Pwm, value); + public void UpdateBrightness(byte value) => Write(Is31fl3730_FunctionRegister.Pwm, value); /// /// Update current setting for each row output of LED matrix (default value is 40 mA). /// - public void UpdateCurrent(Current value) => Write(FunctionRegister.LightingEffect, (byte)value); + public void UpdateCurrent(Current value) => Write(Is31fl3730_FunctionRegister.LightingEffect, (byte)value); /// /// Update configuration register, which controls shutdown, matrix, and display modes. @@ -95,7 +96,7 @@ public void UpdateConfiguration(ShowdownMode shutdown, MatrixMode matrix, Displa configuration |= (byte)shutdown; configuration |= (byte)matrix; configuration |= (byte)display; - Write(FunctionRegister.Configuration, configuration); + Write(Is31fl3730_FunctionRegister.Configuration, configuration); // Set number of and which supported matrices (either or both) if (display is DisplayMode.MatrixOneOnly) @@ -118,7 +119,7 @@ public void UpdateConfiguration(ShowdownMode shutdown, MatrixMode matrix, Displa /// /// Resets all registers to default value. /// - public void ResetRegisters() => Write(FunctionRegister.Reset, MatrixValues.EightBitValue); + public void ResetRegisters() => Write(Is31fl3730_FunctionRegister.Reset, Is31fl3730_MatrixValues.EightBitValue); /// /// Write LED for matrix. @@ -256,8 +257,8 @@ public void WriteDecimalPoint(int matrix, PinValue value) { CheckMatrixIndex(matrix); byte[] buffer = _buffers[matrix]; - int row = matrix is 0 ? MatrixValues.MatrixOneDecimalRow : MatrixValues.MatrixTwoDecimalRow; - byte mask = matrix is 0 ? MatrixValues.MatrixOneDecimalMask : MatrixValues.MatrixTwoDecimalMask; + int row = matrix is 0 ? Is31fl3730_MatrixValues.MatrixOneDecimalRow : Is31fl3730_MatrixValues.MatrixTwoDecimalRow; + byte mask = matrix is 0 ? Is31fl3730_MatrixValues.MatrixOneDecimalMask : Is31fl3730_MatrixValues.MatrixTwoDecimalMask; buffer[row] = UpdateByte(buffer[row], mask, value); AutoFlush(matrix); } @@ -340,7 +341,7 @@ private byte UpdateByte(byte data, byte mask, PinValue value) to the Update Column Register is required to update the Data Registers (01h~0Bh, 0Eh~18h). */ - private void WriteUpdateRegister() => Write(FunctionRegister.UpdateColumn, MatrixValues.EightBitValue); + private void WriteUpdateRegister() => Write(Is31fl3730_FunctionRegister.UpdateColumn, Is31fl3730_MatrixValues.EightBitValue); private void AutoFlush(int matrix) { diff --git a/src/devices/Is31fl3730/MatrixValues.cs b/src/devices/Is31fl3730/MatrixValues.cs index d9b9bf28ce..f58de46170 100644 --- a/src/devices/Is31fl3730/MatrixValues.cs +++ b/src/devices/Is31fl3730/MatrixValues.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Iot.Device.Display +namespace Iot.Device.Display.Internal { /// /// IS31FL3730 matrix driver values. /// - internal static class MatrixValues + internal static class Is31fl3730_MatrixValues { /// /// Arbitrary 8-bit value to write to Update Column Register, as required by datasheet. From 2a81f18d29ad3f393eec877dfd7d40960837bb52 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 25 Jan 2023 20:53:36 -0800 Subject: [PATCH 44/46] Update per feedback --- src/devices/Is31fl3730/FunctionRegister.cs | 2 +- src/devices/Is31fl3730/Is31fl3730.cs | 16 ++++++++-------- src/devices/Is31fl3730/MatrixValues.cs | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/devices/Is31fl3730/FunctionRegister.cs b/src/devices/Is31fl3730/FunctionRegister.cs index 996377aff8..dc8e51d517 100644 --- a/src/devices/Is31fl3730/FunctionRegister.cs +++ b/src/devices/Is31fl3730/FunctionRegister.cs @@ -6,7 +6,7 @@ namespace Iot.Device.Display.Internal /// /// Register addresses for the Function Register. /// - internal static class Is31fl3730_FunctionRegister + internal static class Is31fl3730FunctionRegister { /// /// Address for Configuration Register. diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 69c00f6e11..5aa94e9987 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -20,7 +20,7 @@ namespace Iot.Device.Display // Based on: https://github.com/pimoroni/microdot-phat/blob/master/library/microdotphat/matrix.py public class Is31fl3730 { - private readonly byte[] _matrix_addresses = new byte[] { Is31fl3730_FunctionRegister.Matrix1, Is31fl3730_FunctionRegister.Matrix2 }; + private readonly byte[] _matrix_addresses = new byte[] { Is31fl3730FunctionRegister.Matrix1, Is31fl3730FunctionRegister.Matrix2 }; private readonly List _buffers = new List { new byte[8], @@ -80,12 +80,12 @@ public Is31fl3730(I2cDevice i2cDevice) // Set high bit for the 128th item // Set high bit low for the remaining 127 items // And then set lower bits as appropriate, to represent 0-127 - public void UpdateBrightness(byte value) => Write(Is31fl3730_FunctionRegister.Pwm, value); + public void UpdateBrightness(byte value) => Write(Is31fl3730FunctionRegister.Pwm, value); /// /// Update current setting for each row output of LED matrix (default value is 40 mA). /// - public void UpdateCurrent(Current value) => Write(Is31fl3730_FunctionRegister.LightingEffect, (byte)value); + public void UpdateCurrent(Current value) => Write(Is31fl3730FunctionRegister.LightingEffect, (byte)value); /// /// Update configuration register, which controls shutdown, matrix, and display modes. @@ -96,7 +96,7 @@ public void UpdateConfiguration(ShowdownMode shutdown, MatrixMode matrix, Displa configuration |= (byte)shutdown; configuration |= (byte)matrix; configuration |= (byte)display; - Write(Is31fl3730_FunctionRegister.Configuration, configuration); + Write(Is31fl3730FunctionRegister.Configuration, configuration); // Set number of and which supported matrices (either or both) if (display is DisplayMode.MatrixOneOnly) @@ -119,7 +119,7 @@ public void UpdateConfiguration(ShowdownMode shutdown, MatrixMode matrix, Displa /// /// Resets all registers to default value. /// - public void ResetRegisters() => Write(Is31fl3730_FunctionRegister.Reset, Is31fl3730_MatrixValues.EightBitValue); + public void ResetRegisters() => Write(Is31fl3730FunctionRegister.Reset, Is31fl3730MatrixValues.EightBitValue); /// /// Write LED for matrix. @@ -257,8 +257,8 @@ public void WriteDecimalPoint(int matrix, PinValue value) { CheckMatrixIndex(matrix); byte[] buffer = _buffers[matrix]; - int row = matrix is 0 ? Is31fl3730_MatrixValues.MatrixOneDecimalRow : Is31fl3730_MatrixValues.MatrixTwoDecimalRow; - byte mask = matrix is 0 ? Is31fl3730_MatrixValues.MatrixOneDecimalMask : Is31fl3730_MatrixValues.MatrixTwoDecimalMask; + int row = matrix is 0 ? Is31fl3730MatrixValues.MatrixOneDecimalRow : Is31fl3730MatrixValues.MatrixTwoDecimalRow; + byte mask = matrix is 0 ? Is31fl3730MatrixValues.MatrixOneDecimalMask : Is31fl3730MatrixValues.MatrixTwoDecimalMask; buffer[row] = UpdateByte(buffer[row], mask, value); AutoFlush(matrix); } @@ -341,7 +341,7 @@ private byte UpdateByte(byte data, byte mask, PinValue value) to the Update Column Register is required to update the Data Registers (01h~0Bh, 0Eh~18h). */ - private void WriteUpdateRegister() => Write(Is31fl3730_FunctionRegister.UpdateColumn, Is31fl3730_MatrixValues.EightBitValue); + private void WriteUpdateRegister() => Write(Is31fl3730FunctionRegister.UpdateColumn, Is31fl3730MatrixValues.EightBitValue); private void AutoFlush(int matrix) { diff --git a/src/devices/Is31fl3730/MatrixValues.cs b/src/devices/Is31fl3730/MatrixValues.cs index f58de46170..183e94ae30 100644 --- a/src/devices/Is31fl3730/MatrixValues.cs +++ b/src/devices/Is31fl3730/MatrixValues.cs @@ -6,7 +6,7 @@ namespace Iot.Device.Display.Internal /// /// IS31FL3730 matrix driver values. /// - internal static class Is31fl3730_MatrixValues + internal static class Is31fl3730MatrixValues { /// /// Arbitrary 8-bit value to write to Update Column Register, as required by datasheet. From a4222e87e114cb175054e6d501e614cc7f1e1d2e Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 1 Feb 2023 20:38:31 -0800 Subject: [PATCH 45/46] Fix fill logic --- src/devices/Is31fl3730/Is31fl3730.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index 5aa94e9987..f6cfa57058 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -269,7 +269,7 @@ public void WriteDecimalPoint(int matrix, PinValue value) public void Fill(int matrix, PinValue value) { CheckMatrixIndex(matrix); - _buffers[matrix].AsSpan().Fill((byte)value); + _buffers[matrix].AsSpan().Fill((byte)(value == PinValue.High ? 255 : 0)); AutoFlush(matrix); } From 67ca483f5159220cb9ec3afd1a46c271daf11c70 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Thu, 2 Feb 2023 11:55:54 -0800 Subject: [PATCH 46/46] Update per feedback --- src/devices/Is31fl3730/Is31fl3730.cs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/devices/Is31fl3730/Is31fl3730.cs b/src/devices/Is31fl3730/Is31fl3730.cs index f6cfa57058..e2a605733f 100644 --- a/src/devices/Is31fl3730/Is31fl3730.cs +++ b/src/devices/Is31fl3730/Is31fl3730.cs @@ -80,12 +80,28 @@ public Is31fl3730(I2cDevice i2cDevice) // Set high bit for the 128th item // Set high bit low for the remaining 127 items // And then set lower bits as appropriate, to represent 0-127 - public void UpdateBrightness(byte value) => Write(Is31fl3730FunctionRegister.Pwm, value); + public void UpdateBrightness(byte value) + { + if (value > 128) + { + throw new ArgumentException($"{nameof(value)} must be between 0-128. {nameof(value)} was: {value}."); + } + + Write(Is31fl3730FunctionRegister.Pwm, value); + } /// /// Update current setting for each row output of LED matrix (default value is 40 mA). /// - public void UpdateCurrent(Current value) => Write(Is31fl3730FunctionRegister.LightingEffect, (byte)value); + public void UpdateCurrent(Current value) + { + if (!Enum.IsDefined(typeof(Current), value)) + { + throw new ArgumentException($"{value} is not a valid integer value for {nameof(Current)}."); + } + + Write(Is31fl3730FunctionRegister.LightingEffect, (byte)value); + } /// /// Update configuration register, which controls shutdown, matrix, and display modes.