o Update rpi-rgb-led-matrix to latest version.
o Make it possible to use command-line flags provided by the matrix library.
This commit is contained in:
parent
84359580ad
commit
cac591441f
7 changed files with 242 additions and 143 deletions
171
Config.cpp
171
Config.cpp
|
|
@ -1,9 +1,11 @@
|
|||
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
|
||||
// Matrix configuration parsing class implementation.
|
||||
// Author: Tony DiCola
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <libconfig.h++>
|
||||
|
||||
|
|
@ -11,23 +13,45 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
// Get value if it exists, otherwise return default.
|
||||
static int getWithDefault(const libconfig::Setting& root, const char *key,
|
||||
int default_value) {
|
||||
return root.exists(key) ? root[key] : default_value;
|
||||
}
|
||||
|
||||
Config::Config(const string& filename) {
|
||||
Config::Config(rgb_matrix::RGBMatrix::Options *options,
|
||||
const string& filename)
|
||||
: _moptions(options),
|
||||
_display_width(-1),
|
||||
_display_height(-1),
|
||||
_panel_width(-1),
|
||||
_crop_x(-1),
|
||||
_crop_y(-1)
|
||||
{
|
||||
try {
|
||||
// Load config file with libconfig.
|
||||
libconfig::Config cfg;
|
||||
cfg.readFile(filename.c_str());
|
||||
libconfig::Setting& root = cfg.getRoot();
|
||||
// Parse out the matrix configuration values.
|
||||
_display_width = root["display_width"];
|
||||
_display_height = root["display_height"];
|
||||
_panel_width = root["panel_width"];
|
||||
_panel_height = root["panel_height"];
|
||||
_chain_length = root["chain_length"];
|
||||
_parallel_count = root["parallel_count"];
|
||||
// Set default value for optional config values.
|
||||
_crop_x = -1;
|
||||
_crop_y = -1;
|
||||
// Parse out the matrix configuration values. If not given, we use
|
||||
// reasonable defaults or defaults provided by the flags.
|
||||
_panel_width = getWithDefault(root, "panel_width", 32);
|
||||
_moptions->rows = getWithDefault(root, "panel_height", _moptions->rows);
|
||||
_chain_length = getWithDefault(root, "chain_length",
|
||||
_moptions->chain_length);
|
||||
// While all the code for the transformer assumes number of panels, for
|
||||
// the internal representation for the matrix code, we need to normalize
|
||||
// that to 32 wide panels.
|
||||
_moptions->chain_length = _chain_length * (_panel_width / 32);
|
||||
|
||||
_moptions->parallel = getWithDefault(root, "parallel_count",
|
||||
_moptions->parallel);
|
||||
|
||||
_display_width = getWithDefault(root, "display_width",
|
||||
getPanelWidth() * getChainLength());
|
||||
_display_height = getWithDefault(root, "display_height",
|
||||
getPanelHeight() * getParallelCount());
|
||||
|
||||
// Load optional crop_origin value.
|
||||
if (root.exists("crop_origin")) {
|
||||
libconfig::Setting& crop_origin = root["crop_origin"];
|
||||
|
|
@ -37,79 +61,86 @@ Config::Config(const string& filename) {
|
|||
_crop_x = crop_origin[0];
|
||||
_crop_y = crop_origin[1];
|
||||
}
|
||||
|
||||
// Do basic validation of configuration.
|
||||
if (_panel_width % 32 != 0) {
|
||||
throw invalid_argument("Panel width must be multiple of 32. Typically that is 32, but sometimes 64.");
|
||||
}
|
||||
|
||||
if (_display_width % _panel_width != 0) {
|
||||
throw invalid_argument("display_width must be a multiple of panel_width!");
|
||||
}
|
||||
if (_display_height % _panel_height != 0) {
|
||||
if (_display_height % getPanelHeight() != 0) {
|
||||
throw invalid_argument("display_height must be a multiple of panel_height!");
|
||||
}
|
||||
if ((_parallel_count < 1) || (_parallel_count > 3)) {
|
||||
throw invalid_argument("parallel_count must be between 1 and 3!");
|
||||
std::string message;
|
||||
if (!_moptions->Validate(&message)) {
|
||||
throw invalid_argument(message);
|
||||
}
|
||||
|
||||
// Parse out the individual panel configurations.
|
||||
libconfig::Setting& panels_config = root["panels"];
|
||||
for (int i = 0; i < panels_config.getLength(); ++i) {
|
||||
libconfig::Setting& row = panels_config[i];
|
||||
for (int j = 0; j < row.getLength(); ++j) {
|
||||
GridTransformer::Panel panel;
|
||||
// Read panel order (required setting for each panel).
|
||||
panel.order = row[j]["order"];
|
||||
// Set default values for rotation and parallel chain, then override
|
||||
// them with any panel-specific configuration values.
|
||||
panel.rotate = 0;
|
||||
panel.parallel = 0;
|
||||
row[j].lookupValue("rotate", panel.rotate);
|
||||
row[j].lookupValue("parallel", panel.parallel);
|
||||
// Perform validation of panel values.
|
||||
// If panels are square allow rotations that are a multiple of 90, otherwise
|
||||
// only allow a rotation of 180 degrees.
|
||||
if ((_panel_width == _panel_height) && (panel.rotate % 90 != 0)) {
|
||||
stringstream error;
|
||||
error << "Panel " << i << "," << j << " rotation must be a multiple of 90 degrees!";
|
||||
throw invalid_argument(error.str());
|
||||
if (root.exists("panels")) {
|
||||
libconfig::Setting& panels_config = root["panels"];
|
||||
for (int i = 0; i < panels_config.getLength(); ++i) {
|
||||
libconfig::Setting& row = panels_config[i];
|
||||
for (int j = 0; j < row.getLength(); ++j) {
|
||||
GridTransformer::Panel panel;
|
||||
// Read panel order (required setting for each panel).
|
||||
panel.order = row[j]["order"];
|
||||
// Set default values for rotation and parallel chain, then override
|
||||
// them with any panel-specific configuration values.
|
||||
panel.rotate = 0;
|
||||
panel.parallel = 0;
|
||||
row[j].lookupValue("rotate", panel.rotate);
|
||||
row[j].lookupValue("parallel", panel.parallel);
|
||||
// Perform validation of panel values.
|
||||
// If panels are square allow rotations that are a multiple of 90, otherwise
|
||||
// only allow a rotation of 180 degrees.
|
||||
if ((_panel_width == getPanelHeight()) && (panel.rotate % 90 != 0)) {
|
||||
stringstream error;
|
||||
error << "Panel " << i << "," << j << " rotation must be a multiple of 90 degrees!";
|
||||
throw invalid_argument(error.str());
|
||||
}
|
||||
else if ((_panel_width != getPanelHeight()) && (panel.rotate % 180 != 0)) {
|
||||
stringstream error;
|
||||
error << "Panel row " << j << ", column " << i << " can only be rotated 180 degrees!";
|
||||
throw invalid_argument(error.str());
|
||||
}
|
||||
// Check that parallel is value between 0 and 2 (up to 3 parallel chains).
|
||||
if ((panel.parallel < 0) || (panel.parallel > 2)) {
|
||||
stringstream error;
|
||||
error << "Panel row " << j << ", column " << i << " parallel value must be 0, 1, or 2!";
|
||||
throw invalid_argument(error.str());
|
||||
}
|
||||
// Add the panel to the list of panel configurations.
|
||||
_panels.push_back(panel);
|
||||
}
|
||||
else if ((_panel_width != _panel_height) && (panel.rotate % 180 != 0)) {
|
||||
stringstream error;
|
||||
error << "Panel row " << j << ", column " << i << " can only be rotated 180 degrees!";
|
||||
throw invalid_argument(error.str());
|
||||
}
|
||||
// Check that parallel is value between 0 and 2 (up to 3 parallel chains).
|
||||
if ((panel.parallel < 0) || (panel.parallel > 2)) {
|
||||
stringstream error;
|
||||
error << "Panel row " << j << ", column " << i << " parallel value must be 0, 1, or 2!";
|
||||
throw invalid_argument(error.str());
|
||||
}
|
||||
// Add the panel to the list of panel configurations.
|
||||
_panels.push_back(panel);
|
||||
}
|
||||
// Check the number of configured panels matches the expected number
|
||||
// of panels (# of panel columns * # of panel rows).
|
||||
const int expected = (getDisplayWidth() / getPanelWidth())
|
||||
* (getDisplayHeight() / getPanelHeight());
|
||||
if (_panels.size() != (unsigned int)expected) {
|
||||
stringstream error;
|
||||
error << "Expected " << expected << " panels in configuration but found " << _panels.size() << "!";
|
||||
throw invalid_argument(error.str());
|
||||
}
|
||||
}
|
||||
// Check the number of configured panels matches the expected number
|
||||
// of panels (# of panel columns * # of panel rows).
|
||||
int expected = (_display_width / _panel_width) * (_display_height / _panel_height);
|
||||
if (_panels.size() != (unsigned int)expected) {
|
||||
}
|
||||
catch (const libconfig::FileIOException& fioex) {
|
||||
throw runtime_error("IO error while reading configuration file. Does the file exist?");
|
||||
}
|
||||
catch (const libconfig::ParseException& pex) {
|
||||
stringstream error;
|
||||
error << "Expected " << expected << " panels in configuration but found " << _panels.size() << "!";
|
||||
error << "Config file error at " << pex.getFile() << ":" << pex.getLine()
|
||||
<< " - " << pex.getError();
|
||||
throw invalid_argument(error.str());
|
||||
}
|
||||
catch (const libconfig::SettingNotFoundException& nfex) {
|
||||
stringstream error;
|
||||
error << "Expected to find setting: " << nfex.getPath();
|
||||
throw invalid_argument(error.str());
|
||||
}
|
||||
}
|
||||
catch (const libconfig::FileIOException& fioex)
|
||||
{
|
||||
throw runtime_error("IO error while reading configuration file. Does the file exist?");
|
||||
}
|
||||
catch (const libconfig::ParseException& pex)
|
||||
{
|
||||
stringstream error;
|
||||
error << "Config file error at " << pex.getFile() << ":" << pex.getLine()
|
||||
<< " - " << pex.getError();
|
||||
throw invalid_argument(error.str());
|
||||
}
|
||||
catch (const libconfig::SettingNotFoundException& nfex)
|
||||
{
|
||||
stringstream error;
|
||||
error << "Expected to find setting: " << nfex.getPath();
|
||||
throw invalid_argument(error.str());
|
||||
}
|
||||
catch (const libconfig::ConfigException& ex) {
|
||||
throw runtime_error("Error loading configuration!");
|
||||
}
|
||||
|
|
|
|||
28
Config.h
28
Config.h
|
|
@ -1,3 +1,4 @@
|
|||
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
|
||||
// Matrix configuration parsing class declaration.
|
||||
// Author: Tony DiCola
|
||||
#ifndef CONFIG_H
|
||||
|
|
@ -7,33 +8,41 @@
|
|||
#include <vector>
|
||||
|
||||
#include "GridTransformer.h"
|
||||
#include "led-matrix.h"
|
||||
|
||||
class Config {
|
||||
public:
|
||||
Config(const std::string& filename);
|
||||
Config(rgb_matrix::RGBMatrix::Options *options,
|
||||
const std::string& filename);
|
||||
|
||||
// Attribute accessors:
|
||||
int getDisplayWidth() const {
|
||||
return _display_width;
|
||||
return (_display_width < 0)
|
||||
? getPanelWidth() * getChainLength()
|
||||
: _display_width;
|
||||
}
|
||||
int getDisplayHeight() const {
|
||||
return _display_height;
|
||||
return (_display_height < 0)
|
||||
? getPanelHeight() * getParallelCount()
|
||||
: _display_height;
|
||||
}
|
||||
int getPanelWidth() const {
|
||||
return _panel_width;
|
||||
return (_panel_width) < 0 ? 32 : _panel_width;
|
||||
}
|
||||
int getPanelHeight() const {
|
||||
return _panel_height;
|
||||
return _moptions->rows;
|
||||
}
|
||||
int getChainLength() const {
|
||||
return _chain_length;
|
||||
}
|
||||
int getParallelCount() const {
|
||||
return _parallel_count;
|
||||
return _moptions->parallel;
|
||||
}
|
||||
bool hasTransformer() const { return !_panels.empty(); }
|
||||
GridTransformer getGridTransformer() const {
|
||||
return GridTransformer(_display_width, _display_height, _panel_width,
|
||||
_panel_height, _chain_length, _panels);
|
||||
return GridTransformer(getDisplayWidth(), getDisplayHeight(),
|
||||
getPanelWidth(), getPanelHeight(),
|
||||
getChainLength(), _panels);
|
||||
}
|
||||
bool hasCropOrigin() const {
|
||||
return (_crop_x > -1) && (_crop_y > -1);
|
||||
|
|
@ -46,12 +55,11 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
rgb_matrix::RGBMatrix::Options* const _moptions;
|
||||
int _display_width,
|
||||
_display_height,
|
||||
_panel_width,
|
||||
_panel_height,
|
||||
_chain_length,
|
||||
_parallel_count,
|
||||
_crop_x,
|
||||
_crop_y;
|
||||
std::vector<GridTransformer::Panel> _panels;
|
||||
|
|
|
|||
15
Makefile
15
Makefile
|
|
@ -1,13 +1,16 @@
|
|||
# Configure the rpi-rgb-led-matrix library here:
|
||||
# The -DADAFRUIT_RGBMATRIX_HAT value configures the library to use the Adafruit
|
||||
# LED matrix HAT wiring, and the -DRGB_SLOWDOWN_GPIO=1 value configures the
|
||||
# library to work with a Raspberry Pi 2. For a Pi 1 (or perhaps even on a Pi 2,
|
||||
# but I found it necessary in my testing) you can remove the -DRGB_SLOWDOWN_GPIO=1
|
||||
# option. You can also add any other rpi-rgb-led-matrix library defines here
|
||||
# The HARDWARE_DESC=adafruit-hat value configures the library to use the
|
||||
# Adafruit LED matrix HAT wiring, and the -DRGB_SLOWDOWN_GPIO=1 value configures
|
||||
# the library to work with a Raspberry Pi 2. For a Pi 1 (or perhaps even on
|
||||
# a Pi 2, but I found it necessary in my testing) you can remove the
|
||||
# -DRGB_SLOWDOWN_GPIO=1 option (You also can set this value at runtime via the
|
||||
# command line option --led-slowdown-gpio=1).
|
||||
# You can also add any other rpi-rgb-led-matrix library defines here
|
||||
# to configure the library for more special needs. See the library's docs for
|
||||
# details on options:
|
||||
# https://github.com/hzeller/rpi-rgb-led-matrix/blob/master/lib/Makefile
|
||||
export DEFINES = -DADAFRUIT_RGBMATRIX_HAT -DRGB_SLOWDOWN_GPIO=1
|
||||
export HARDWARE_DESC=adafruit-hat
|
||||
export USER_DEFINES=-DRGB_SLOWDOWN_GPIO=1
|
||||
|
||||
# Configure compiler and libraries:
|
||||
CXX = g++
|
||||
|
|
|
|||
36
README.md
36
README.md
|
|
@ -27,11 +27,41 @@ Build the project by running make:
|
|||
|
||||
Once compiled there will be two executables:
|
||||
|
||||
* rpi-fb-matrix: The main program that will copy the contents of the primary
|
||||
* `rpi-fb-matrix`: The main program that will copy the contents of the primary
|
||||
display (HDMI output) to attached LED matrices.
|
||||
* display-test: A program to display the order and orientation of chained
|
||||
* `display-test`: A program to display the order and orientation of chained
|
||||
together LED matrices. Good for building complex display chains.
|
||||
|
||||
Both executables understand the standard command line flags provided in the
|
||||
rpi-rgb-led-matrix library, for instance for choosing the gpio mapping.
|
||||
The default compile-choice gpio mapping is `adafruit-hat`, but you can change
|
||||
that to any [supported gpio mapping] depending on your set-up.
|
||||
|
||||
The [configuration file](./matrix.cfg) allows to describe the geometry and
|
||||
panel-layout. It overrides geometry-related settings provided as flags
|
||||
(e.g. `--led-chain`).
|
||||
|
||||
You can get a list of available command line options by giving `--led-help`
|
||||
```
|
||||
$ ./rpi-fb-matrix --led-help
|
||||
Usage: ./rpi-fb-matrix [flags] [config-file]
|
||||
Flags:
|
||||
--led-gpio-mapping=<name> : Name of GPIO mapping used. Default "adafruit-hat"
|
||||
--led-rows=<rows> : Panel rows. 8, 16, 32 or 64. (Default: 32).
|
||||
--led-chain=<chained> : Number of daisy-chained panels. (Default: 1).
|
||||
--led-parallel=<parallel> : For A/B+ models or RPi2,3b: parallel chains. range=1..3 (Default: 1).
|
||||
--led-pwm-bits=<1..11> : PWM bits (Default: 11).
|
||||
--led-brightness=<percent>: Brightness in percent (Default: 100).
|
||||
--led-scan-mode=<0..1> : 0 = progressive; 1 = interlaced (Default: 0).
|
||||
--led-show-refresh : Show refresh rate.
|
||||
--led-inverse : Switch if your matrix has inverse colors on.
|
||||
--led-swap-green-blue : Switch if your matrix has green/blue swapped on.
|
||||
--led-pwm-lsb-nanoseconds : PWM Nanoseconds for LSB (Default: 130)
|
||||
--led-no-hardware-pulse : Don't use hardware pin-pulse generation.
|
||||
--led-slowdown-gpio=<0..2>: Slowdown GPIO. Needed for faster Pis and/or slower panels (Default: 1).
|
||||
--led-daemon : Make the process run in the background as daemon.
|
||||
```
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
This program makes use of the following excellent libraries:
|
||||
|
|
@ -44,3 +74,5 @@ Framebuffer capture code based on information from the [rpi-fbcp](https://github
|
|||
## License
|
||||
|
||||
Released under the GPL v2.0 license, see LICENSE.txt for details.
|
||||
|
||||
[supported gpio mapping]: https://github.com/hzeller/rpi-rgb-led-matrix/blob/master/lib/Makefile#L19
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
|
||||
// Program to aid in the testing of LED matrix chains.
|
||||
// Author: Tony DiCola
|
||||
#include <cstdint>
|
||||
|
|
@ -17,13 +18,13 @@ using namespace std;
|
|||
using namespace rgb_matrix;
|
||||
|
||||
|
||||
bool running = true; // Global to keep track of if the program should run.
|
||||
// Will be set false by a SIGINT handler when ctrl-c is
|
||||
// pressed, then the main loop will cleanly exit.
|
||||
// Global to keep track of if the program should run.
|
||||
// Will be set false by a SIGINT handler when ctrl-c is
|
||||
// pressed, then the main loop will cleanly exit.
|
||||
volatile bool running = true;
|
||||
|
||||
|
||||
void printCanvas(Canvas& canvas, int x, int y, const string& message,
|
||||
int r = 255, int g = 255, int b = 255) {
|
||||
void printCanvas(Canvas* canvas, int x, int y, const string& message,
|
||||
int r = 255, int g = 255, int b = 255) {
|
||||
// Loop through all the characters and print them starting at the provided
|
||||
// coordinates.
|
||||
for (auto c: message) {
|
||||
|
|
@ -35,7 +36,7 @@ void printCanvas(Canvas& canvas, int x, int y, const string& message,
|
|||
for (int j=0; j<8; ++j) {
|
||||
// Put a pixel for each 1 in the column byte.
|
||||
if ((col >> j) & 0x01) {
|
||||
canvas.SetPixel(x, y+j, r, g, b);
|
||||
canvas->SetPixel(x, y+j, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,20 +45,28 @@ void printCanvas(Canvas& canvas, int x, int y, const string& message,
|
|||
}
|
||||
}
|
||||
|
||||
void sigintHandler(int s) {
|
||||
static void sigintHandler(int s) {
|
||||
running = false;
|
||||
}
|
||||
|
||||
static void usage(const char* progname) {
|
||||
std::cerr << "Usage: " << progname << " [flags] [config-file]" << std::endl;
|
||||
std::cerr << "Flags:" << std::endl;
|
||||
rgb_matrix::PrintMatrixFlags(stderr);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
try
|
||||
{
|
||||
// Expect one command line parameter with display configuration filename.
|
||||
if (argc != 2) {
|
||||
throw runtime_error("Expected configuration file name as only command line parameter!\r\nUsage: display-test /path/to/display/config.cfg");
|
||||
try {
|
||||
// Initialize from flags.
|
||||
rgb_matrix::RGBMatrix::Options matrix_options;
|
||||
rgb_matrix::RuntimeOptions runtime_options;
|
||||
if (!rgb_matrix::ParseOptionsFromFlags(&argc, &argv,
|
||||
&matrix_options, &runtime_options)) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load the configuration.
|
||||
Config config(argv[1]);
|
||||
Config config(&matrix_options, argc >= 2 ? argv[1] : "/dev/null");
|
||||
cout << "Using config values: " << endl
|
||||
<< " display_width: " << config.getDisplayWidth() << endl
|
||||
<< " display_height: " << config.getDisplayHeight() << endl
|
||||
|
|
@ -67,21 +76,25 @@ int main(int argc, char** argv) {
|
|||
<< " parallel_count: " << config.getParallelCount() << endl;
|
||||
|
||||
// Initialize matrix library.
|
||||
GPIO io;
|
||||
if (!io.Init()) {
|
||||
throw runtime_error("Failed to initialize rpi-led-matrix library! Make sure to run as root with sudo.");
|
||||
// Create canvas and apply GridTransformer.
|
||||
RGBMatrix *canvas = CreateMatrixFromOptions(matrix_options, runtime_options);
|
||||
|
||||
int panel_rows = config.getParallelCount();
|
||||
int panel_columns = config.getChainLength();
|
||||
if (config.hasTransformer()) {
|
||||
GridTransformer grid = config.getGridTransformer();
|
||||
canvas->ApplyStaticTransformer(grid);
|
||||
panel_rows = grid.getRows();
|
||||
panel_columns = grid.getColumns();
|
||||
}
|
||||
|
||||
// Create canvas and apply GridTransformer.
|
||||
RGBMatrix canvas(&io, config.getPanelHeight(), config.getChainLength(),
|
||||
config.getParallelCount());
|
||||
GridTransformer grid = config.getGridTransformer();
|
||||
canvas.SetTransformer(&grid);
|
||||
cout << "Panel rows: " << panel_rows << endl
|
||||
<< "Panel cols: " << panel_columns << endl;
|
||||
|
||||
// Clear the canvas, then draw on each panel.
|
||||
canvas.Fill(0, 0, 0);
|
||||
for (int i=0; i<grid.getRows(); ++i) {
|
||||
for (int j=0; j<grid.getColumns(); ++j) {
|
||||
canvas->Fill(0, 0, 0);
|
||||
for (int i=0; i<panel_columns; ++i) {
|
||||
for (int j=0; j<panel_rows; ++j) {
|
||||
// Compute panel origin position.
|
||||
int x = i*config.getPanelWidth();
|
||||
int y = j*config.getPanelHeight();
|
||||
|
|
@ -97,10 +110,12 @@ int main(int argc, char** argv) {
|
|||
while (running) {
|
||||
sleep(1);
|
||||
}
|
||||
canvas.Clear();
|
||||
canvas->Clear();
|
||||
delete canvas;
|
||||
}
|
||||
catch (const exception& ex) {
|
||||
cerr << ex.what() << endl;
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
|
||||
// Program to copy the contents of the Raspberry Pi primary display to LED matrices.
|
||||
// Author: Tony DiCola
|
||||
#include <iostream>
|
||||
|
|
@ -19,11 +20,10 @@
|
|||
using namespace std;
|
||||
using namespace rgb_matrix;
|
||||
|
||||
|
||||
bool running = true; // Global to keep track of if the program should run.
|
||||
// Will be set false by a SIGINT handler when ctrl-c is
|
||||
// pressed, then the main loop will cleanly exit.
|
||||
|
||||
// Global to keep track of if the program should run.
|
||||
// Will be set false by a SIGINT handler when ctrl-c is
|
||||
// pressed, then the main loop will cleanly exit.
|
||||
volatile bool running = true;
|
||||
|
||||
// Class to encapsulate all the logic for capturing an image of the Pi's primary
|
||||
// display. Manages all the BCM GPU and CPU resources automatically while in scope.
|
||||
|
|
@ -104,21 +104,33 @@ private:
|
|||
uint8_t* _screen_data;
|
||||
};
|
||||
|
||||
|
||||
void sigintHandler(int s) {
|
||||
static void sigintHandler(int s) {
|
||||
running = false;
|
||||
}
|
||||
|
||||
static void usage(const char* progname) {
|
||||
std::cerr << "Usage: " << progname << " [flags] [config-file]" << std::endl;
|
||||
std::cerr << "Flags:" << std::endl;
|
||||
rgb_matrix::RGBMatrix::Options matrix_options;
|
||||
rgb_matrix::RuntimeOptions runtime_options;
|
||||
runtime_options.drop_privileges = -1; // Need root
|
||||
rgb_matrix::PrintMatrixFlags(stderr, matrix_options, runtime_options);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
try
|
||||
{
|
||||
// Expect one command line parameter with display configuration filename.
|
||||
if (argc != 2) {
|
||||
throw runtime_error("Expected configuration file name as only command line parameter!\r\nUsage: rpi-fb-matrix /path/to/display/config.cfg");
|
||||
try {
|
||||
// Initialize from flags.
|
||||
rgb_matrix::RGBMatrix::Options matrix_options;
|
||||
rgb_matrix::RuntimeOptions runtime_options;
|
||||
runtime_options.drop_privileges = -1; // Need root
|
||||
if (!rgb_matrix::ParseOptionsFromFlags(&argc, &argv,
|
||||
&matrix_options, &runtime_options)) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load the configuration.
|
||||
Config config(argv[1]);
|
||||
// Read additional configuration from config file if it exists
|
||||
Config config(&matrix_options, argc >= 2 ? argv[1] : "/dev/null");
|
||||
cout << "Using config values: " << endl
|
||||
<< " display_width: " << config.getDisplayWidth() << endl
|
||||
<< " display_height: " << config.getDisplayHeight() << endl
|
||||
|
|
@ -144,18 +156,14 @@ int main(int argc, char** argv) {
|
|||
y_offset = config.getCropY();
|
||||
}
|
||||
|
||||
// Initialize matrix library.
|
||||
GPIO io;
|
||||
if (!io.Init()) {
|
||||
throw runtime_error("Failed to initialize rpi-led-matrix library! Make sure to run as root with sudo.");
|
||||
}
|
||||
|
||||
// Initialize matrix library.
|
||||
// Create canvas and apply GridTransformer.
|
||||
RGBMatrix canvas(&io, config.getPanelHeight(), config.getChainLength(),
|
||||
config.getParallelCount());
|
||||
GridTransformer grid = config.getGridTransformer();
|
||||
canvas.SetTransformer(&grid);
|
||||
canvas.Clear();
|
||||
RGBMatrix *canvas = CreateMatrixFromOptions(matrix_options, runtime_options);
|
||||
if (config.hasTransformer()) {
|
||||
canvas->ApplyStaticTransformer(config.getGridTransformer());
|
||||
}
|
||||
canvas->Clear();
|
||||
|
||||
// Initialize BCM functions and display capture class.
|
||||
bcm_host_init();
|
||||
|
|
@ -172,16 +180,18 @@ int main(int argc, char** argv) {
|
|||
for (int x=0; x<config.getDisplayWidth(); ++x) {
|
||||
uint8_t red, green, blue;
|
||||
displayCapture.getPixel(x+x_offset, y+y_offset, &red, &green, &blue);
|
||||
canvas.SetPixel(x, y, red, green, blue);
|
||||
canvas->SetPixel(x, y, red, green, blue);
|
||||
}
|
||||
}
|
||||
// Sleep for 25 milliseconds.
|
||||
// Sleep for 25 milliseconds (40Hz refresh)
|
||||
usleep(25 * 1000);
|
||||
}
|
||||
canvas.Clear();
|
||||
canvas->Clear();
|
||||
delete canvas;
|
||||
}
|
||||
catch (const exception& ex) {
|
||||
cerr << ex.what() << endl;
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 5cdf1b4954aed4ea8b9d7fb57f3d1f410201408d
|
||||
Subproject commit 3080a773e771db7489aa49455f58f3dade186949
|
||||
Loading…
Reference in a new issue