001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.wpilibj;
006
007import edu.wpi.first.wpilibj.util.Color;
008import edu.wpi.first.wpilibj.util.Color8Bit;
009
010/** Buffer storage for Addressable LEDs. */
011public class AddressableLEDBuffer {
012  byte[] m_buffer;
013
014  /**
015   * Constructs a new LED buffer with the specified length.
016   *
017   * @param length The length of the buffer in pixels
018   */
019  public AddressableLEDBuffer(int length) {
020    m_buffer = new byte[length * 4];
021  }
022
023  /**
024   * Sets a specific led in the buffer.
025   *
026   * @param index the index to write
027   * @param r the r value [0-255]
028   * @param g the g value [0-255]
029   * @param b the b value [0-255]
030   */
031  public void setRGB(int index, int r, int g, int b) {
032    m_buffer[index * 4] = (byte) b;
033    m_buffer[(index * 4) + 1] = (byte) g;
034    m_buffer[(index * 4) + 2] = (byte) r;
035    m_buffer[(index * 4) + 3] = 0;
036  }
037
038  /**
039   * Sets a specific led in the buffer.
040   *
041   * @param index the index to write
042   * @param h the h value [0-180)
043   * @param s the s value [0-255]
044   * @param v the v value [0-255]
045   */
046  public void setHSV(final int index, final int h, final int s, final int v) {
047    if (s == 0) {
048      setRGB(index, v, v, v);
049      return;
050    }
051
052    // The below algorithm is copied from Color.fromHSV and moved here for
053    // performance reasons.
054
055    // Loosely based on
056    // https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
057    // The hue range is split into 60 degree regions where in each region there
058    // is one rgb component at a low value (m), one at a high value (v) and one
059    // that changes (X) from low to high (X+m) or high to low (v-X)
060
061    // Difference between highest and lowest value of any rgb component
062    final int chroma = (s * v) / 255;
063
064    // Beacuse hue is 0-180 rather than 0-360 use 30 not 60
065    final int region = (h / 30) % 6;
066
067    // Remainder converted from 0-30 to 0-255
068    final int remainder = (int) Math.round((h % 30) * (255 / 30.0));
069
070    // Value of the lowest rgb component
071    final int m = v - chroma;
072
073    // Goes from 0 to chroma as hue increases
074    final int X = (chroma * remainder) >> 8;
075
076    switch (region) {
077      case 0:
078        setRGB(index, v, X + m, m);
079        break;
080      case 1:
081        setRGB(index, v - X, v, m);
082        break;
083      case 2:
084        setRGB(index, m, v, X + m);
085        break;
086      case 3:
087        setRGB(index, m, v - X, v);
088        break;
089      case 4:
090        setRGB(index, X + m, m, v);
091        break;
092      default:
093        setRGB(index, v, m, v - X);
094        break;
095    }
096  }
097
098  /**
099   * Sets a specific LED in the buffer.
100   *
101   * @param index The index to write
102   * @param color The color of the LED
103   */
104  public void setLED(int index, Color color) {
105    setRGB(index, (int) (color.red * 255), (int) (color.green * 255), (int) (color.blue * 255));
106  }
107
108  /**
109   * Sets a specific LED in the buffer.
110   *
111   * @param index The index to write
112   * @param color The color of the LED
113   */
114  public void setLED(int index, Color8Bit color) {
115    setRGB(index, color.red, color.green, color.blue);
116  }
117
118  /**
119   * Gets the buffer length.
120   *
121   * @return the buffer length
122   */
123  public int getLength() {
124    return m_buffer.length / 4;
125  }
126
127  /**
128   * Gets the color at the specified index.
129   *
130   * @param index the index to get
131   * @return the LED color at the specified index
132   */
133  public Color8Bit getLED8Bit(int index) {
134    return new Color8Bit(
135        m_buffer[index * 4 + 2] & 0xFF, m_buffer[index * 4 + 1] & 0xFF, m_buffer[index * 4] & 0xFF);
136  }
137
138  /**
139   * Gets the color at the specified index.
140   *
141   * @param index the index to get
142   * @return the LED color at the specified index
143   */
144  public Color getLED(int index) {
145    return new Color(
146        (m_buffer[index * 4 + 2] & 0xFF) / 255.0,
147        (m_buffer[index * 4 + 1] & 0xFF) / 255.0,
148        (m_buffer[index * 4] & 0xFF) / 255.0);
149  }
150}