Skip to content
This repository has been archived by the owner on Jun 13, 2020. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
mp911de committed Oct 23, 2015
1 parent 095d348 commit 0623012
Show file tree
Hide file tree
Showing 21 changed files with 2,360 additions and 759 deletions.
35 changes: 31 additions & 4 deletions rpi-rgb-led-matrix/Makefile
@@ -1,5 +1,7 @@
CXXFLAGS=-Wall -O3 -g
BINARIES=led-matrix text-example
OBJECTS=demo-main.o minimal-example.o text-example.o led-image-viewer.o
BINARIES=led-matrix minimal-example text-example
ALL_BINARIES=$(BINARIES) led-image-viewer

# Where our library resides. It is split between includes and the binary
# library in lib
Expand All @@ -9,20 +11,45 @@ RGB_LIBRARY_NAME=rgbmatrix
RGB_LIBRARY=$(RGB_LIBDIR)/lib$(RGB_LIBRARY_NAME).a
LDFLAGS+=-L$(RGB_LIBDIR) -l$(RGB_LIBRARY_NAME) -lrt -lm -lpthread

PYTHON_LIB_DIR=python

# Imagemagic flags, only needed if actually compiled.
MAGICK_CXXFLAGS=`GraphicsMagick++-config --cppflags --cxxflags`
MAGICK_LDFLAGS=`GraphicsMagick++-config --ldflags --libs`

all : $(BINARIES)

$(RGB_LIBRARY):
$(RGB_LIBRARY): FORCE
$(MAKE) -C $(RGB_LIBDIR)

led-matrix : matrix-main.o $(RGB_LIBRARY)
$(CXX) $(CXXFLAGS) matrix-main.o -o $@ $(LDFLAGS)

minimal-example : minimal-example.o $(RGB_LIBRARY)
$(CXX) $(CXXFLAGS) minimal-example.o -o $@ $(LDFLAGS)

text-example : text-example.o $(RGB_LIBRARY)
$(CXX) $(CXXFLAGS) text-example.o -o $@ $(LDFLAGS)

led-image-viewer: led-image-viewer.o $(RGB_LIBRARY)
$(CXX) $(CXXFLAGS) led-image-viewer.o -o $@ $(LDFLAGS) $(MAGICK_LDFLAGS)

%.o : %.cc
$(CXX) -I$(RGB_INCDIR) $(CXXFLAGS) -c -o $@ $<

led-image-viewer.o : led-image-viewer.cc
$(CXX) -I$(RGB_INCDIR) $(CXXFLAGS) $(MAGICK_CXXFLAGS) -c -o $@ $<

clean:
rm -f $(OBJECTS) $(BINARIES)
$(MAKE) -C lib clean
rm -f $(OBJECTS) $(ALL_BINARIES)
$(MAKE) -C lib clean
$(MAKE) -C $(PYTHON_LIB_DIR) clean

build-python: $(RGB_LIBRARY)
$(MAKE) -C $(PYTHON_LIB_DIR) build

install-python: build-python
$(MAKE) -C $(PYTHON_LIB_DIR) install

FORCE:
.PHONY: FORCE
488 changes: 350 additions & 138 deletions rpi-rgb-led-matrix/README.md

Large diffs are not rendered by default.

42 changes: 38 additions & 4 deletions rpi-rgb-led-matrix/include/canvas.h
Expand Up @@ -20,10 +20,15 @@
namespace rgb_matrix {
// An interface for things a Canvas can do. The RGBMatrix implements this
// interface, so you can use it directly wherever a canvas is needed.
// However, this abstraction allows you to e.g. create delegating
// implementations that do a particular transformation, e.g. compose images,
// scale, rotate, anti-alias or translate coordinates in a funky way.
// So it might be a good idea to have your demos write to a Canvas instead.
//
// This abstraction also allows you to e.g. create delegating
// implementations that do a particular transformation, e.g. re-map
// pixels (as you might lay out the physical RGB matrix in a different way),
// compose images (OR, XOR, transparecy), scale, rotate, anti-alias or
// translate coordinates in a funky way.
//
// It is a good idea to have your applications use the concept of
// a Canvas to write the content to instead of directly using the RGBMatrix.
class Canvas {
public:
virtual ~Canvas() {}
Expand All @@ -43,5 +48,34 @@ class Canvas {
virtual void Fill(uint8_t red, uint8_t green, uint8_t blue) = 0;
};

// A canvas transformer is an object that, given a Canvas, returns a
// canvas that applies transformations before writing to the original
// Canvas.
//
// To simplify assumptions for implementations and users of implementations,
// the following conditions and constraints apply:
//
// 1) The CanvasTransformer _never_ takes ownership of the delegatee.
// 2) The ownership of the returned Canvas is _not_ passed to the caller.
// 3) The returned Canvas can only be assumed to be valid for the lifetime
// of the CanvasTranformer and the lifetime of the original canvas.
// 4) The returned canvas is only valid up to the next call of Transform().
//
// * Point 2)-4) imply that the CanvasTransformer can hand out the same
// canvas object every time, just configured to write to the new
// delegatee.
// * Point 4) implies that one instance of CanvasTransformer cannot be used in
// parallel in multiple threads calling Transform().
// * The constraints also imply that it is valid for a CanvasTransformer to
// return the passed in canvas itself.
class CanvasTransformer {
public:
virtual ~CanvasTransformer() {}

// Return a Canvas* that applies transformations before delegating to
// the output canvas.
virtual Canvas *Transform(Canvas *output) = 0;
};

} // namespace rgb_matrix
#endif // RPI_CANVAS_H
45 changes: 43 additions & 2 deletions rpi-rgb-led-matrix/include/gpio.h
Expand Up @@ -18,6 +18,8 @@

#include <stdint.h>

#include <vector>

// Putting this in our namespace to not collide with other things called like
// this.
namespace rgb_matrix {
Expand All @@ -39,12 +41,26 @@ class GPIO {

// Set the bits that are '1' in the output. Leave the rest untouched.
inline void SetBits(uint32_t value) {
gpio_port_[0x1C / sizeof(uint32_t)] = value;
if (!value) return;
*gpio_set_bits_ = value;
#ifdef RGB_SLOWDOWN_GPIO
*gpio_set_bits_ = value;
# if RGB_SLOWDOWN_GPIO > 1
*gpio_set_bits_ = value; // for really slow cases
# endif
#endif
}

// Clear the bits that are '1' in the output. Leave the rest untouched.
inline void ClearBits(uint32_t value) {
gpio_port_[0x28 / sizeof(uint32_t)] = value;
if (!value) return;
*gpio_clr_bits_ = value;
#ifdef RGB_SLOWDOWN_GPIO
*gpio_clr_bits_ = value;
# if RGB_SLOWDOWN_GPIO > 1
*gpio_clr_bits_ = value; // for really slow cases
# endif
#endif
}

// Write all the bits of "value" mentioned in "mask". Leave the rest untouched.
Expand All @@ -60,6 +76,31 @@ class GPIO {
private:
uint32_t output_bits_;
volatile uint32_t *gpio_port_;
volatile uint32_t *gpio_set_bits_;
volatile uint32_t *gpio_clr_bits_;
};

// A PinPulser is a utility class that pulses a GPIO pin. There can be various
// implementations.
class PinPulser {
public:
// Factory for a PinPulser. Chooses the right implementation depending
// on the context (CPU and which pins are affected).
// "gpio_mask" is the mask that should be output (since we only
// need negative pulses, this is what it does)
// "nano_wait_spec" contains a list of time periods we'd like
// invoke later. This can be used to pre-process timings if needed.
static PinPulser *Create(GPIO *io, uint32_t gpio_mask,
const std::vector<int> &nano_wait_spec);

virtual ~PinPulser() {}

// Send a pulse with a given length (index into nano_wait_spec array).
virtual void SendPulse(int time_spec_number) = 0;

// If SendPulse() is asynchronously implemented, wait for pulse to finish.
virtual void WaitPulseFinished() {}
};

} // end namespace rgb_matrix
#endif // RPI_GPIO_H
8 changes: 7 additions & 1 deletion rpi-rgb-led-matrix/include/graphics.h
Expand Up @@ -49,6 +49,8 @@ class Font {
int DrawGlyph(Canvas *c, int x, int y, const Color &color,
uint32_t unicode_codepoint) const;
private:
Font(const Font& x); // No copy constructor. Use references or pointer instead.

struct Glyph;
typedef std::map<uint32_t, Glyph*> CodepointGlyphMap;

Expand All @@ -66,7 +68,11 @@ class Font {
int DrawText(Canvas *c, const Font &font, int x, int y, const Color &color,
const char *utf8_text);

// lines, circles and stuff.
// Draw a circle centered at "x", "y", with a radius of "radius" and with "color"
void DrawCircle(Canvas *c, int xx, int y, int radius, const Color &color);

// Draw a line from "x0", "y0" to "x1", "y1" and with "color"
void DrawLine(Canvas *c, int x0, int y0, int x1, int y1, const Color &color);

} // namespace rgb_matrix

Expand Down
135 changes: 123 additions & 12 deletions rpi-rgb-led-matrix/include/led-matrix.h
Expand Up @@ -13,42 +13,112 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://gnu.org/licenses/gpl-2.0.txt>

// Controlling a 32x32 RGB matrix via GPIO.
// Controlling 16x32 or 32x32 RGB matrixes via GPIO. It allows daisy chaining
// of a string of these, and also connecting a parallel string on newer
// Raspberry Pis with more GPIO pins available.

#ifndef RPI_RGBMATRIX_H
#define RPI_RGBMATRIX_H

#include <stdint.h>
#include <vector>

#include "gpio.h"
#include "canvas.h"
#include "thread.h"
#include "transformer.h"

namespace rgb_matrix {
class FrameCanvas; // Canvas for Double- and Multibuffering
namespace internal { class Framebuffer; }

// The RGB matrix provides the framebuffer and the facilities to constantly
// update the LED matrix.
//
// This implement the Canvas interface that represents the display with
// (32 * chained_displays)x(rows * parallel_displays) pixels.
//
// If can do multi-buffering using the CreateFrameCanvas() and SwapOnVSync()
// methods. This is useful for animations and to prevent tearing.
//
// If you arrange the panels in a different way in the physical space, write
// a delegating Canvas that does coordinate remapping, like the
// LargeSquare64x64Canvas in demo-main.cc.
class RGBMatrix : public Canvas {
public:
// Initialize RGB matrix with GPIO to write to. The "rows" are the number
// Initialize RGB matrix with GPIO to write to.
//
// The "rows" are the number
// of rows supported by the display, so 32 or 16. Number of "chained_display"s
// tells many of these are daisy-chained together.
// tells many of these are daisy-chained together (output of one connected
// to input of next).
//
// The "parallel_display" number determines if there is one or two displays
// connected in parallel to the GPIO port - this only works with newer
// Raspberry Pi that have 40 interface pins.
//
// If "io" is not NULL, starts refreshing the screen immediately; you can
// defer that by setting GPIO later with SetGPIO().
RGBMatrix(GPIO *io, int rows = 32, int chained_displays = 1);
//
// The resulting canvas is (rows * parallel_displays) high and
// (32 * chained_displays) wide.
RGBMatrix(GPIO *io, int rows = 32, int chained_displays = 1,
int parallel_displays = 1);
virtual ~RGBMatrix();

// Set GPIO output if it was not set already in constructor (oterwise: no-op).
// Set GPIO output if it was not set already in constructor (otherwise: NoOp).
// Starts display refresh thread if this is the first setting.
void SetGPIO(GPIO *io);

// Set PWM bits used for output. Default is 11, but if you only deal with
// simple comic-colors, 1 might be sufficient. Lower require less CPU.
// limited comic-colors, 1 might be sufficient. Lower require less CPU and
// increases refresh-rate.
//
// Returns boolean to signify if value was within range.
//
// This sets the PWM bits for the current active FrameCanvas and future
// ones that are created with CreateFrameCanvas().
bool SetPWMBits(uint8_t value);
uint8_t pwmbits();
uint8_t pwmbits(); // return the pwm-bits of the currently active buffer.

// Map brightness of output linearly to input with CIE1931 profile.
void set_luminance_correct(bool on);
bool luminance_correct() const;

// Set brightness in percent. 1%..100%.
// This will only affect newly set pixels.
void SetBrightness(uint8_t brightness);
uint8_t brightness();

//-- Double- and Multibuffering.

// Create a new buffer to be used for multi-buffering. The returned new
// Buffer implements a Canvas with the same size of thie RGBMatrix.
// You can use it to draw off-screen on it, then swap it with the active
// buffer using SwapOnVSync(). That would be classic double-buffering.
//
// You can also create as many FrameCanvas as you like and for instance use
// them to pre-fill scenes of an animation for fast playback later.
//
// The ownership of the created Canvases remains with the RGBMatrix, so you
// don't have to worry about deleting them.
FrameCanvas *CreateFrameCanvas();

// This method waits to the next VSync and swaps the active buffer with the
// supplied buffer. The formerly active buffer is returned.
//
// If you pass in NULL, the active buffer is returned, but it won't be
// replaced with NULL. You can use the NULL-behavior to just wait on
// VSync or to retrieve the initial buffer when preparing a multi-buffer
// animation.
FrameCanvas *SwapOnVSync(FrameCanvas *other);

// Set image transformer that maps the logical canvas we provide to the
// physical canvas (e.g. panel mapping, rotation ...).
// Does _not_ take ownership of the transformer.
void SetTransformer(CanvasTransformer *transformer);
inline CanvasTransformer *transformer() { return transformer_; }

// -- Canvas interface. These write to the active FrameCanvas
// (see documentation in canvas.h)
virtual int width() const;
Expand All @@ -59,17 +129,58 @@ class RGBMatrix : public Canvas {
virtual void Fill(uint8_t red, uint8_t green, uint8_t blue);

private:
class Framebuffer;
class UpdateThread;
friend class UpdateThread;
friend class FrameCanvas;

// Updates the screen regularly.
void UpdateScreen();
const int rows_;
const int chained_displays_;
const int parallel_displays_;

uint8_t pwm_bits_;
bool do_luminance_correct_;
uint8_t brightness_;

FrameCanvas *active_;

Framebuffer *frame_;
GPIO *io_;
Mutex active_frame_sync_;
UpdateThread *updater_;
std::vector<FrameCanvas*> created_frames_;
CanvasTransformer *transformer_;
};

class FrameCanvas : public Canvas {
public:
// Set PWM bits used for this Frame.
// Simple comic-colors, 1 might be sufficient (111 RGB, i.e. 8 colors).
// Lower require less CPU.
// Returns boolean to signify if value was within range.
bool SetPWMBits(uint8_t value);
uint8_t pwmbits();

// Map brightness of output linearly to input with CIE1931 profile.
void set_luminance_correct(bool on);
bool luminance_correct() const;

void SetBrightness(uint8_t brightness);
uint8_t brightness();

// -- Canvas interface.
virtual int width() const;
virtual int height() const;
virtual void SetPixel(int x, int y,
uint8_t red, uint8_t green, uint8_t blue);
virtual void Clear();
virtual void Fill(uint8_t red, uint8_t green, uint8_t blue);

private:
friend class RGBMatrix;

FrameCanvas(internal::Framebuffer *frame) : frame_(frame){}
virtual ~FrameCanvas();
internal::Framebuffer *framebuffer() { return frame_; }

internal::Framebuffer *const frame_;
};
} // end namespace rgb_matrix
#endif // RPI_RGBMATRIX_H

0 comments on commit 0623012

Please sign in to comment.