Things used in this project

Code

Driver CodeC#
Interfaces to the Sense Hat to drive the LEDs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.I2c;
using Windows.Devices.Gpio;

namespace AstroPi
{
    public class LedHatFb : IDisposable
    {
        public const byte ADDRESS = 0x46;

        #region IDisposable Support
        public void Dispose()
        {
            if (_LedHatFbDevice != null)
            {
                _LedHatFbDevice.Dispose();
                _LedHatFbDevice = null;
            }
        }
        #endregion

        private I2cDevice _LedHatFbDevice = null;

        private byte [] _gamma = {
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
          0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07,
          0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x11,
          0x12, 0x14, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F};

        private byte[] _inverse_gamma = {
            0x00, 0x06, 0x08, 0x0A, 0x0C, 0x0D, 0x0E, 0x0F,
            0x10, 0x11, 0x12, 0x13, 0x14, 0x14, 0x15, 0x16,
            0x16, 0x17, 0x18, 0x18, 0x19, 0x1A, 0x1A, 0x1B,
            0x1B, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F};

        public async void InitHardware()
        {
            try
            {
                string aqs = I2cDevice.GetDeviceSelector();
                DeviceInformationCollection collection = await DeviceInformation.FindAllAsync(aqs);

                I2cConnectionSettings settings = new I2cConnectionSettings(ADDRESS);
                settings.BusSpeed = I2cBusSpeed.StandardMode; // 100kHz clock
                settings.SharingMode = I2cSharingMode.Exclusive;
                _LedHatFbDevice = await I2cDevice.FromIdAsync(collection[0].Id, settings);
            }
            catch (Exception ex)
            {
                string error = ex.ToString();
            }
        }

        public void MapToHat(byte [] output, int outputOffset, byte [] input, int inputOffset)
        {
            for(int i=0;i<8;i++)
            {
                int co = inputOffset + i * 4;
                byte blue = input[co];
                byte green = input[co+1];
                byte red = input[co+2];
                byte alpha = input[co + 3];

                output[outputOffset + i] = (byte)(red);
                output[outputOffset + i + 8] = (byte)(green);
                output[outputOffset + i + 16] = (byte)(blue);
            }
        }

        #region low level

        private byte ReadByte(byte regAddr)
        {
            byte[] buffer = new byte[1];
            buffer[0] = regAddr;
            byte[] value = new byte[1];
            _LedHatFbDevice.WriteRead(buffer, value);
            return value[0];
        }

        private byte[] ReadBytes(byte regAddr, int length)
        {
            byte[] values = new byte[length];
            byte[] buffer = new byte[1];
            buffer[0] = regAddr;
            _LedHatFbDevice.WriteRead(buffer, values);
            return values;
        }

        void WriteByte(byte regAddr, byte data)
        {
            byte[] buffer = new byte[2];
            buffer[0] = regAddr;
            buffer[1] = data;
            _LedHatFbDevice.Write(buffer);
        }

        void WriteBytes(byte regAddr, byte[] values)
        {
            byte[] buffer = new byte[1 + values.Length];
            buffer[0] = regAddr;
            Array.Copy(values, 0, buffer, 1, values.Length);
            _LedHatFbDevice.Write(buffer);
        }

        #endregion

        public void WriteLEDs(int address, byte[] buffer)
        {
            if (buffer.Length + address > 192)
            {
                throw new ArgumentException("Address outside range (address + buffer length must be <= 192", "buffer");
            }
            if (address < 0)
            {
                throw new ArgumentException("Address can't be less than zero", "address");
            }
            byte[] b = new byte[buffer.Length];
            for (int i = 0; i < buffer.Length; i++)
            {
                b[i] = _gamma[buffer[i] >> 3];
            }
            WriteBytes((byte)address, b);
        }

        public void WriteLEDMatrix(byte [] buffer)
        {
            WriteLEDs(0, buffer);
        }

        public byte [] ReadLEDs(int address, int size)
        {
            if (size + address > 192)
            {
                throw new ArgumentException("Address outside range (address + size length must be <= 192", "size");
            }
            if (address < 0)
            {
                throw new ArgumentException("Address can't be less than zero", "address");
            }
            byte[] b = ReadBytes((byte)address, size);
            byte[] buffer = new byte[b.Length];
            for (int i = 0; i < b.Length; i++)
            {
                buffer[i] = (byte)(_inverse_gamma[b[i] & 0x1F] << 3);
            }
            return buffer;
        }

        public byte[] ReadLEDMatrix()
        {
            return ReadLEDs(0, 192);
        }

        public byte ReadWai()
        {
            return ReadByte(0xf0);
        }

        public byte ReadVersion()
        {
            return ReadByte(0xf1);
        }

        public byte ReadKeys()
        {
            return ReadByte(0xf2);
        }

        public byte ReadEEWp()
        {
            return ReadByte(0xf4);
        }

        // no idea what this does, maybe hold off using it
        public void WriteEEEp(byte value)
        {
            WriteByte(0xf4, value);
        }

        // no idea what this does, maybe hold off using it
        public void WriteAddress(byte value)
        {
            WriteByte(0xff, value);
        }

    }
}
MainC#
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.Graphics.Imaging;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace AstroPi
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        private LedHatFb _ledHat = new LedHatFb();
        public MainPage()
        {
            this.InitializeComponent();
            _ledHat.InitHardware();
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            byte ver = _ledHat.ReadVersion();
            byte k = _ledHat.ReadKeys();
            byte wai = _ledHat.ReadWai();
            byte eewp = _ledHat.ReadEEWp();

            LoadBitmap("ms-appx:///assets/rp.png");
        }

        private async void LoadBitmap(string name)
        {
            StorageFile srcfile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(name));

            using (IRandomAccessStream fileStream = await srcfile.OpenAsync(Windows.Storage.FileAccessMode.Read))
            {
                BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
                BitmapTransform transform = new BitmapTransform()
                {
                    ScaledWidth = 8,
                    ScaledHeight = 8
                };
                PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
                    BitmapPixelFormat.Bgra8,
                    BitmapAlphaMode.Straight,
                    transform,
                    ExifOrientationMode.IgnoreExifOrientation,
                    ColorManagementMode.DoNotColorManage
                );

                byte[] sourcePixels = pixelData.DetachPixelData();
                byte[] hatPixels = new byte[192];

                for(int i=0;i<(sourcePixels.Length/4)/8; i++)
                {
                    _ledHat.MapToHat(hatPixels, i * 8 * 3, sourcePixels, i * 8 * 4);
                }
                _ledHat.WriteLEDMatrix(hatPixels);
            }
        }

        private void Page_Unloaded(object sender, RoutedEventArgs e)
        {
            _ledHat.Dispose();
        }

        private void FlipButton_Click(object sender, RoutedEventArgs e)
        {
            byte[] read_buffer;
            read_buffer = _ledHat.ReadLEDMatrix();
            byte[] write_buffer = new byte[192];
            for (int i = 0; i < 192; i++)
            {
                write_buffer[i] = (byte)(0xFF - read_buffer[i]);
            }
            _ledHat.WriteLEDMatrix(write_buffer);
        }

        private void DimButton_Click(object sender, RoutedEventArgs e)
        {
            byte[] read_buffer;
            read_buffer = _ledHat.ReadLEDMatrix();
            byte[] write_buffer = new byte[192];
            for (int i = 0; i < 192; i++)
            {
                byte v = read_buffer[i];
                write_buffer[i] = (byte)(v);
            }
            _ledHat.WriteLEDMatrix(write_buffer);
        }
    }
}

Credits

Logo 300x300
Graham Chow

I'm a software developer on a long sabbatical. I've had wide experience from banking to underwater military sonar systems.

Contact

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Similar projects you might like

Hey Mycroft, Where Is the International Space Station?
Easy
  • 1,751
  • 36

Full instructions

Developing my first skill with the Mycroft.ai open source voice assistant on a Raspberry Pi 3 - aka Picroft!

Setup SQL Anywhere on Raspberry Pi
Easy
  • 148
  • 3

Protip

Setup of SQL Anywhere on Raspberry Pi to allow collecting and processing sensor data offline on the edge, plus synchronizing when online.

Measure Plant Grow
Easy
  • 1,081
  • 16

Find out how plants grow without killing the plant.

Run Telegram on Raspberry Pi
Easy
  • 154
  • 2

Protip

How to run Telegram on Raspberry Pi 2 and Raspberry Pi 3. Step-by-step instruction.

How to Add Alexa to a Raspberry Pi
Easy
  • 2,267
  • 21

Full instructions

Solution that allows turning any Linux-based device into an Amazon Echo.

Piano Hero Game Using Android Things
Easy
  • 276
  • 5

Learn to play the piano with a MIDI keyboard and Android Things that includes your favourite nursery rhymes and Disney songs.

ProjectsCommunitiesTopicsContestsLiveAppsBetaFree StoreBlogAdd projectSign up / Login