mirror of
https://github.com/Hopiu/rpi-rgb-led-matrix.git
synced 2026-03-16 22:10:27 +00:00
o Add some common runtim options (--led-daemon, --led-drop-privs)
o Add more options for matrix parameters (--led-brightness, --led-pwm-bits)
This commit is contained in:
parent
edce0acadb
commit
7557c40e17
8 changed files with 239 additions and 267 deletions
2
Makefile
2
Makefile
|
|
@ -25,6 +25,8 @@ $(RGB_LIBRARY): FORCE
|
|||
|
||||
clean:
|
||||
$(MAKE) -C lib clean
|
||||
$(MAKE) -C examples-api-use clean
|
||||
$(MAKE) -C utils clean
|
||||
$(MAKE) -C $(PYTHON_LIB_DIR) clean
|
||||
|
||||
build-python: $(RGB_LIBRARY)
|
||||
|
|
|
|||
|
|
@ -1017,22 +1017,12 @@ static int usage(const char *progname) {
|
|||
fprintf(stderr, "usage: %s <options> -D <demo-nr> [optional parameter]\n",
|
||||
progname);
|
||||
fprintf(stderr, "Options:\n");
|
||||
RGBMatrix::Options::FlagUsageMessage();
|
||||
fprintf(stderr,
|
||||
"\t-L : 'Large' display, composed out of 4 times 32x32\n"
|
||||
"\t-p <pwm-bits> : Bits used for PWM. Something between 1..11\n"
|
||||
"\t-D <demo-nr> : Always needs to be set\n"
|
||||
"\t-d : run as daemon. Use this when starting "
|
||||
"in\n"
|
||||
"\t /etc/init.d, but also when "
|
||||
"running without\n"
|
||||
"\t terminal (e.g. cron).\n"
|
||||
"\t-t <seconds> : Run for these number of seconds, then exit.\n"
|
||||
"\t (if neither -d nor -t are supplied, "
|
||||
"waits for <RETURN>)\n"
|
||||
"\t-b <brightnes> : Sets brightness percent. Default: 100.\n"
|
||||
"\t-R <rotation> : Sets the rotation of matrix. "
|
||||
"Allowed: 0, 90, 180, 270. Default: 0.\n");
|
||||
rgb_matrix::PrintMatrixOptions(stderr);
|
||||
fprintf(stderr, "Demos, choosen with -D\n");
|
||||
fprintf(stderr, "\t0 - some rotating square\n"
|
||||
"\t1 - forward scrolling an image (-m <scroll-ms>)\n"
|
||||
|
|
@ -1052,36 +1042,23 @@ static int usage(const char *progname) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GPIO io;
|
||||
bool as_daemon = false;
|
||||
// First things first: create matrix and take command line flags.
|
||||
RGBMatrix *matrix = CreateMatrixFromFlags(&argc, &argv);
|
||||
|
||||
int runtime_seconds = -1;
|
||||
int demo = -1;
|
||||
RGBMatrix::Options options;
|
||||
int scroll_ms = 30;
|
||||
int pwm_bits = -1;
|
||||
int brightness = 100;
|
||||
int rotation = 0;
|
||||
bool large_display = false;
|
||||
bool do_luminance_correct = true;
|
||||
|
||||
const char *demo_parameter = NULL;
|
||||
|
||||
// First, let's consume the flags for the options.
|
||||
if (!options.InitializeFromFlags(&argc, &argv)) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
bool any_deprecated_option = false;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "dlD:t:r:P:c:p:b:m:LR:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "dD:t:r:P:c:p:b:m:LR:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'D':
|
||||
demo = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
as_daemon = true;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
runtime_seconds = atoi(optarg);
|
||||
break;
|
||||
|
|
@ -1090,49 +1067,39 @@ int main(int argc, char *argv[]) {
|
|||
scroll_ms = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
pwm_bits = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
brightness = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
do_luminance_correct = !do_luminance_correct;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
// The 'large' display assumes a chain of four displays with 32x32
|
||||
options.chain_length = 4;
|
||||
options.rows = 32;
|
||||
large_display = true;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
rotation = atoi(optarg);
|
||||
break;
|
||||
|
||||
// These used to be options we understood, but deprecate now. Accept them
|
||||
// for now, but tell the user.
|
||||
// These used to be options we understood, but deprecated now. Tell user.
|
||||
case 'r':
|
||||
options.rows = atoi(optarg);
|
||||
fprintf(stderr, TERM_ERR "-r is a deprecated option. "
|
||||
"Please use --led-rows=%d instead!\n" TERM_NORM, options.rows);
|
||||
fprintf(stderr, "-r is a deprecated option. "
|
||||
"Please use --led-rows=... instead!\n");
|
||||
any_deprecated_option = true;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
options.parallel = atoi(optarg);
|
||||
fprintf(stderr, TERM_ERR "-P is a deprecated option. "
|
||||
"Please use --led-parallel=%d instead!\n" TERM_NORM,
|
||||
options.parallel);
|
||||
fprintf(stderr, "-P is a deprecated option. "
|
||||
"Please use --led-parallel=... instead!\n");
|
||||
any_deprecated_option = true;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
options.chain_length = atoi(optarg);
|
||||
fprintf(stderr, TERM_ERR "-c is a deprecated option. "
|
||||
"Please use --led-chain=%d instead!\n" TERM_NORM,
|
||||
options.chain_length);
|
||||
fprintf(stderr, "-c is a deprecated option. "
|
||||
"Please use --led-chain=... instead!\n");
|
||||
any_deprecated_option = true;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
fprintf(stderr, "-p is a deprecated option. "
|
||||
"Please use --led-pwm-bits=... instead!\n");
|
||||
any_deprecated_option = true;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
fprintf(stderr, "-b is a deprecated option. "
|
||||
"Please use --led-brightness=... instead!\n");
|
||||
any_deprecated_option = true;
|
||||
break;
|
||||
|
||||
default: /* '?' */
|
||||
|
|
@ -1140,69 +1107,31 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
if (any_deprecated_option)
|
||||
return usage(argv[0]);
|
||||
|
||||
if (optind < argc) {
|
||||
demo_parameter = argv[optind];
|
||||
}
|
||||
|
||||
std::string err;
|
||||
if (!options.Validate(&err)) {
|
||||
fprintf(stderr, "%s", err.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (demo < 0) {
|
||||
fprintf(stderr, TERM_ERR "Expected required option -D <demo>\n" TERM_NORM);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
if (brightness < 1 || brightness > 100) {
|
||||
fprintf(stderr, TERM_ERR "Brightness is outside usable range.\n" TERM_NORM);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (rotation % 90 != 0) {
|
||||
fprintf(stderr, TERM_ERR "Rotation %d not allowed! "
|
||||
"Only 0, 90, 180 and 270 are possible.\n" TERM_NORM, rotation);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getuid() != 0) {
|
||||
fprintf(stderr, TERM_ERR "Must run as root to be able to access /dev/mem\n"
|
||||
"Prepend 'sudo' to the command:\n\tsudo %s ...\n" TERM_NORM,
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize GPIO pins. This might fail when we don't have permissions.
|
||||
if (!io.Init())
|
||||
return 1;
|
||||
|
||||
// Start daemon before we start any threads.
|
||||
if (as_daemon) {
|
||||
if (fork() != 0)
|
||||
return 0;
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
}
|
||||
|
||||
// The matrix, our 'frame buffer' and display updater.
|
||||
RGBMatrix *matrix = new RGBMatrix(&io, options);
|
||||
matrix->set_luminance_correct(do_luminance_correct);
|
||||
matrix->SetBrightness(brightness);
|
||||
if (pwm_bits >= 0 && !matrix->SetPWMBits(pwm_bits)) {
|
||||
fprintf(stderr, "Invalid range of pwm-bits\n");
|
||||
if (matrix == NULL)
|
||||
return 1;
|
||||
}
|
||||
|
||||
LinkedTransformer *transformer = new LinkedTransformer();
|
||||
matrix->SetTransformer(transformer);
|
||||
|
||||
if (large_display) {
|
||||
// Mapping the coordinates of a 32x128 display mapped to a square of 64x64
|
||||
transformer->AddTransformer(new LargeSquare64x64Transformer());
|
||||
}
|
||||
|
||||
if (rotation > 0) {
|
||||
transformer->AddTransformer(new RotateTransformer(rotation));
|
||||
}
|
||||
|
|
@ -1278,9 +1207,7 @@ int main(int argc, char *argv[]) {
|
|||
// Now, the image generation runs in the background. We can do arbitrary
|
||||
// things here in parallel. In this demo, we're essentially just
|
||||
// waiting for one of the conditions to exit.
|
||||
if (as_daemon) {
|
||||
sleep(runtime_seconds > 0 ? runtime_seconds : INT_MAX);
|
||||
} else if (runtime_seconds > 0) {
|
||||
if (runtime_seconds > 0) {
|
||||
sleep(runtime_seconds);
|
||||
} else {
|
||||
// Things are set up. Just wait for <RETURN> to be pressed.
|
||||
|
|
|
|||
|
|
@ -36,28 +36,10 @@ static void DrawOnCanvas(Canvas *canvas) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/*
|
||||
* Set up GPIO pins. This fails when not running as root.
|
||||
*/
|
||||
GPIO io;
|
||||
if (!io.Init())
|
||||
Canvas *canvas = rgb_matrix::CreateMatrixFromFlags(&argc, &argv);
|
||||
if (canvas == NULL)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Set up the RGBMatrix. It implements a 'Canvas' interface.
|
||||
*/
|
||||
RGBMatrix::Options options;
|
||||
if (!options.InitializeFromFlags(&argc, &argv)) {
|
||||
options.FlagUsageMessage();
|
||||
return 1;
|
||||
}
|
||||
std::string err;
|
||||
if (!options.Validate(&err)) {
|
||||
fprintf(stderr, "%s", err.c_str());
|
||||
return 1;
|
||||
}
|
||||
Canvas *canvas = new RGBMatrix(&io, options);
|
||||
|
||||
DrawOnCanvas(canvas); // Using the canvas.
|
||||
|
||||
// Animation finished. Shut down the RGB matrix.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ static int usage(const char *progname) {
|
|||
fprintf(stderr, "Reads text from stdin and displays it. "
|
||||
"Empty string: clear screen\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
RGBMatrix::Options::FlagUsageMessage();
|
||||
rgb_matrix::PrintMatrixOptions(stderr);
|
||||
fprintf(stderr,
|
||||
"\t-f <font-file> : Use given font.\n"
|
||||
"\t-b <brightness> : Sets brightness percent. Default: 100.\n"
|
||||
|
|
@ -35,18 +35,14 @@ static bool parseColor(Color *c, const char *str) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
RGBMatrix *canvas = rgb_matrix::CreateMatrixFromFlags(&argc, &argv);
|
||||
|
||||
Color color(255, 255, 0);
|
||||
const char *bdf_font_file = NULL;
|
||||
RGBMatrix::Options options;
|
||||
int x_orig = 0;
|
||||
int y_orig = -1;
|
||||
int brightness = 100;
|
||||
|
||||
// First, let's consume the flags for the options.
|
||||
if (!options.InitializeFromFlags(&argc, &argv)) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "x:y:f:C:b:")) != -1) {
|
||||
switch (opt) {
|
||||
|
|
@ -65,6 +61,9 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
if (canvas == NULL)
|
||||
return 1;
|
||||
|
||||
if (bdf_font_file == NULL) {
|
||||
fprintf(stderr, "Need to specify BDF font-file with -f\n");
|
||||
return usage(argv[0]);
|
||||
|
|
@ -79,28 +78,11 @@ int main(int argc, char *argv[]) {
|
|||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
std::string err;
|
||||
if (!options.Validate(&err)) {
|
||||
fprintf(stderr, "%s", err.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (brightness < 1 || brightness > 100) {
|
||||
fprintf(stderr, "Brightness is outside usable range.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up GPIO pins. This fails when not running as root.
|
||||
*/
|
||||
GPIO io;
|
||||
if (!io.Init())
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Set up the RGBMatrix. It implements a 'Canvas' interface.
|
||||
*/
|
||||
RGBMatrix *canvas = new RGBMatrix(&io, options);
|
||||
canvas->SetBrightness(brightness);
|
||||
|
||||
bool all_extreme_colors = brightness == 100;
|
||||
|
|
|
|||
|
|
@ -30,9 +30,34 @@
|
|||
#include "transformer.h"
|
||||
|
||||
namespace rgb_matrix {
|
||||
class RGBMatrix;
|
||||
class FrameCanvas; // Canvas for Double- and Multibuffering
|
||||
namespace internal { class Framebuffer; }
|
||||
|
||||
// Convenience factory utility to create a Matrix and set values from the
|
||||
// command line. You pass it a pointer to the argc and argv of main, it
|
||||
// extracts the relevant options and leaves the remaining options.
|
||||
//
|
||||
// Example use:
|
||||
/*
|
||||
using rgb_matrix::RGBMatrix;
|
||||
int main(int argc, char **argv) {
|
||||
RGBMatrix *matrix = rgb_matrix::CreateMatrixFromFlags(&argc, &argv);
|
||||
if (matrix == NULL) {
|
||||
PrintMatrixOptions(stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Do your own command line handling with the remaining options.
|
||||
|
||||
// .. now use matrix
|
||||
|
||||
delete matrix; // Make sure to delete it in the end.
|
||||
}
|
||||
*/
|
||||
RGBMatrix *CreateMatrixFromFlags(int *argc, char ***argv);
|
||||
void PrintMatrixOptions(FILE *out);
|
||||
|
||||
// The RGB matrix provides the framebuffer and the facilities to constantly
|
||||
// update the LED matrix.
|
||||
//
|
||||
|
|
@ -51,23 +76,9 @@ public:
|
|||
struct Options {
|
||||
Options(); // Creates a default option set.
|
||||
|
||||
// Validate the options and possibly output a message to
|
||||
// Validate the options and possibly output a message to string.
|
||||
bool Validate(std::string *err);
|
||||
|
||||
// --led_rows, --led_chain, --led_parallel
|
||||
// This modifies the argc and argv, so use in main such as
|
||||
// int main(int argc, char *argv[]) {
|
||||
// RGBMatrix::Options options;
|
||||
// if (!options.InitializeFromFlags(&argc, &argv)) {
|
||||
// return 1;
|
||||
// }
|
||||
// // ... now do the relevant stuff.
|
||||
// }
|
||||
bool InitializeFromFlags(int *argc, char ***argv);
|
||||
|
||||
// Usage message that explains the available flags.
|
||||
static void FlagUsageMessage();
|
||||
|
||||
// The "rows" are the number
|
||||
// of rows supported by the display, so 32 or 16. Default: 32.
|
||||
int rows;
|
||||
|
|
@ -81,6 +92,15 @@ public:
|
|||
// also be 2 or 3. The effective number of pixels in vertical direction is
|
||||
// then thus rows * parallel. Default: 1
|
||||
int parallel;
|
||||
|
||||
// Set PWM bits used for output. Default is 11, but if you only deal with
|
||||
// limited comic-colors, 1 might be sufficient. Lower require less CPU and
|
||||
// increases refresh-rate.
|
||||
int pwm_bits;
|
||||
|
||||
// The initial brightness of the panel in percent. Valid range is 1..100
|
||||
// Default: 100
|
||||
int brightness;
|
||||
};
|
||||
|
||||
// Create an RGBMatrix.
|
||||
|
|
|
|||
|
|
@ -120,11 +120,14 @@ private:
|
|||
};
|
||||
|
||||
// Some defaults. See options-initialize.cc for the command line parsing.
|
||||
RGBMatrix::Options::Options() : rows(32), chain_length(1), parallel(1) {}
|
||||
RGBMatrix::Options::Options()
|
||||
: rows(32), chain_length(1), parallel(1), pwm_bits(11), brightness(100) {}
|
||||
|
||||
RGBMatrix::RGBMatrix(GPIO *io, const Options &options)
|
||||
: rows_(options.rows), chained_displays_(options.chain_length),
|
||||
parallel_displays_(options.parallel),
|
||||
pwm_bits_(options.pwm_bits),
|
||||
brightness_(options.brightness),
|
||||
io_(NULL), updater_(NULL) {
|
||||
SetTransformer(NULL);
|
||||
active_ = CreateFrameCanvas();
|
||||
|
|
|
|||
|
|
@ -14,15 +14,31 @@
|
|||
// along with this program. If not, see <http://gnu.org/licenses/gpl-2.0.txt>
|
||||
|
||||
#include "led-matrix.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace rgb_matrix {
|
||||
namespace {
|
||||
typedef char** argv_iterator;
|
||||
|
||||
static bool ConsumeBoolFlag(const char *flag_name, const argv_iterator &pos,
|
||||
bool *result_value) {
|
||||
const char *option = *pos;
|
||||
const size_t flag_len = strlen(flag_name);
|
||||
if (strncmp(option, flag_name, flag_len) != 0)
|
||||
return false; // not consumed.
|
||||
*result_value = !*result_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ConsumeIntFlag(const char *flag_name,
|
||||
argv_iterator &pos, const argv_iterator end,
|
||||
int *result_value, int *error) {
|
||||
|
|
@ -53,7 +69,16 @@ static bool ConsumeIntFlag(const char *flag_name,
|
|||
return true; // consumed.
|
||||
}
|
||||
|
||||
static bool OptFlagInit(int &argc, char **&argv, RGBMatrix::Options *mopts) {
|
||||
struct RuntimeOptions {
|
||||
RuntimeOptions() : as_daemon(false), drop_privileges(false) {}
|
||||
|
||||
bool as_daemon;
|
||||
bool drop_privileges;
|
||||
};
|
||||
|
||||
static bool FlagInit(int &argc, char **&argv,
|
||||
RGBMatrix::Options *mopts,
|
||||
RuntimeOptions *ropts) {
|
||||
argv_iterator it = &argv[0];
|
||||
argv_iterator end = it + argc;
|
||||
|
||||
|
|
@ -71,6 +96,14 @@ static bool OptFlagInit(int &argc, char **&argv, RGBMatrix::Options *mopts) {
|
|||
continue;
|
||||
if (ConsumeIntFlag("--led-parallel", it, end, &mopts->parallel, &err))
|
||||
continue;
|
||||
if (ConsumeIntFlag("--led-brightness", it, end, &mopts->brightness, &err))
|
||||
continue;
|
||||
if (ConsumeIntFlag("--led-pwm-bits", it, end, &mopts->pwm_bits, &err))
|
||||
continue;
|
||||
if (ConsumeBoolFlag("--led-daemon", it, &ropts->as_daemon))
|
||||
continue;
|
||||
if (ConsumeBoolFlag("--led-drop-privs", it, &ropts->drop_privileges))
|
||||
continue;
|
||||
}
|
||||
unused_options.push_back(*it);
|
||||
}
|
||||
|
|
@ -86,43 +119,118 @@ static bool OptFlagInit(int &argc, char **&argv, RGBMatrix::Options *mopts) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool RGBMatrix::Options::InitializeFromFlags(int *argc, char ***argv) {
|
||||
// Unfortunately, we can't use getopt_long(), as it does not provide a
|
||||
// way to only fish out some of the flags and leave the rest as-is without
|
||||
// much complaining. So we have to do this here ourselves.
|
||||
return OptFlagInit(*argc, *argv, this);
|
||||
static bool drop_privs(const char *priv_user, const char *priv_group) {
|
||||
uid_t ruid, euid, suid;
|
||||
if (getresuid(&ruid, &euid, &suid) >= 0) {
|
||||
if (euid != 0) // not root anyway. No priv dropping.
|
||||
return true;
|
||||
}
|
||||
|
||||
struct group *g = getgrnam(priv_group);
|
||||
if (g == NULL) {
|
||||
perror("group lookup.");
|
||||
return false;
|
||||
}
|
||||
if (setresgid(g->gr_gid, g->gr_gid, g->gr_gid) != 0) {
|
||||
perror("setresgid()");
|
||||
return false;
|
||||
}
|
||||
struct passwd *p = getpwnam(priv_user);
|
||||
if (p == NULL) {
|
||||
perror("user lookup.");
|
||||
return false;
|
||||
}
|
||||
if (setresuid(p->pw_uid, p->pw_uid, p->pw_uid) != 0) {
|
||||
perror("setresuid()");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RGBMatrix::Options::FlagUsageMessage() {
|
||||
fprintf(stderr,
|
||||
"\t--led-rows <rows> : Panel rows. 8, 16, 32 or 64. "
|
||||
} // namespace
|
||||
|
||||
// Public interface.
|
||||
RGBMatrix *CreateMatrixFromFlags(int *argc, char ***argv) {
|
||||
RGBMatrix::Options mopt;
|
||||
RuntimeOptions ropt;
|
||||
if (!FlagInit(*argc, *argv, &mopt, &ropt)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string error;
|
||||
if (!mopt.Validate(&error)) {
|
||||
fprintf(stderr, "%s\n", error.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (getuid() != 0) {
|
||||
fprintf(stderr, "Must run as root to be able to access /dev/mem\n"
|
||||
"Prepend 'sudo' to the command:\n\tsudo %s ...\n", (*argv)[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GPIO io; // This static var is a little bit icky.
|
||||
if (!io.Init()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ropt.as_daemon && daemon(1, 0) != 0) {
|
||||
perror("Failed to become daemon");
|
||||
}
|
||||
|
||||
RGBMatrix *result = new RGBMatrix(&io, mopt);
|
||||
|
||||
if (ropt.drop_privileges) {
|
||||
drop_privs("daemon", "daemon");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PrintMatrixOptions(FILE *out) {
|
||||
fprintf(out,
|
||||
"\t--led-rows=<rows> : Panel rows. 8, 16, 32 or 64. "
|
||||
"Default: 32\n"
|
||||
"\t--led-parallel <parallel> : For Plus-models or RPi2: parallel "
|
||||
"\t--led-chain=<chained> : Number of daisy-chained panels. "
|
||||
"Default: 1.\n"
|
||||
"\t--led-parallel=<parallel> : For A/B+ models or RPi2,3b: parallel "
|
||||
"chains. 1..3. Default: 1\n"
|
||||
"\t--led-chain <chained> : Number of daisy-chained boards. "
|
||||
"Default: 1.\n");
|
||||
"\t--led-pwm-bits=<1..11> : PWM bits. Default: 11\n"
|
||||
"\t--led-brightness=<percent>: Brightness in percent. Default: 100.\n"
|
||||
"\t--led-drop-privs : Drop privileges from 'root'.\n"
|
||||
"\t--led-daemon : Make the process run as daemon.\n");
|
||||
}
|
||||
|
||||
bool RGBMatrix::Options::Validate(std::string *err) {
|
||||
bool any_error = false;
|
||||
bool success = true;
|
||||
if (rows != 8 && rows != 16 && rows != 32 && rows != 64) {
|
||||
err->append("Invalid number or panel rows. "
|
||||
"Should be one of 8, 16, 32 or 64\n");
|
||||
any_error = true;
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (chain_length < 1) {
|
||||
err->append("Chain-length outside usable range\n");
|
||||
any_error = true;
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (parallel < 1 || parallel > 3) {
|
||||
err->append("Parallel outside usable range.\n");
|
||||
any_error = true;
|
||||
success = false;
|
||||
}
|
||||
return !any_error;
|
||||
|
||||
if (brightness < 1 || brightness > 100) {
|
||||
err->append("Brightness is outside usable range.\n");
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (pwm_bits <= 0 || pwm_bits > 11) {
|
||||
err->append("Invalid range of pwm-bits\n");
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace rgb_matrix
|
||||
|
|
|
|||
|
|
@ -151,62 +151,47 @@ static void DisplayAnimation(const std::vector<PreprocessedFrame*> &frames,
|
|||
static int usage(const char *progname) {
|
||||
fprintf(stderr, "usage: %s [options] <image>\n", progname);
|
||||
fprintf(stderr, "Options:\n");
|
||||
RGBMatrix::Options::FlagUsageMessage();
|
||||
fprintf(stderr,
|
||||
"\t-L : Large 64x64 display made "
|
||||
"from four 32x32 in a chain\n"
|
||||
"\t-d : Run as daemon.\n"
|
||||
"\t-b <brightnes> : Sets brightness percent. "
|
||||
"Default: 100.\n");
|
||||
rgb_matrix::PrintMatrixOptions(stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Magick::InitializeMagick(*argv);
|
||||
RGBMatrix *const matrix = rgb_matrix::CreateMatrixFromFlags(&argc, &argv);
|
||||
|
||||
RGBMatrix::Options options;
|
||||
int pwm_bits = -1;
|
||||
int brightness = 100;
|
||||
bool large_display = false; // example for using Transformers
|
||||
bool as_daemon = false;
|
||||
|
||||
// First, let's consume the flags for the options.
|
||||
if (!options.InitializeFromFlags(&argc, &argv)) {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
// These used to be options we understood, but deprecate now. Accept them
|
||||
// for now, but tell the user.
|
||||
bool any_deprecated_option = false;
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "r:P:c:p:b:dL")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "r:P:c:p:b:d")) != -1) {
|
||||
switch (opt) {
|
||||
case 'p': pwm_bits = atoi(optarg); break;
|
||||
case 'd': as_daemon = true; break;
|
||||
case 'b': brightness = atoi(optarg); break;
|
||||
case 'L':
|
||||
options.chain_length = 4;
|
||||
options.rows = 32;
|
||||
large_display = true;
|
||||
break;
|
||||
|
||||
// These used to be options we understood, but deprecate now. Accept them
|
||||
// for now, but tell the user.
|
||||
case 'r':
|
||||
options.rows = atoi(optarg);
|
||||
fprintf(stderr, TERM_ERR "-r is a deprecated option. "
|
||||
"Please use --led-rows=%d instead!\n" TERM_NORM, options.rows);
|
||||
fprintf(stderr, "-r is a deprecated option. "
|
||||
"Please use --led-rows=... instead!\n");
|
||||
any_deprecated_option = true;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
options.parallel = atoi(optarg);
|
||||
fprintf(stderr, TERM_ERR "-P is a deprecated option. "
|
||||
"Please use --led-parallel=%d instead!\n" TERM_NORM,
|
||||
options.parallel);
|
||||
fprintf(stderr, "-P is a deprecated option. "
|
||||
"Please use --led-parallel=... instead!\n");
|
||||
any_deprecated_option = true;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
options.chain_length = atoi(optarg);
|
||||
fprintf(stderr, TERM_ERR "-c is a deprecated option. "
|
||||
"Please use --led-chain=%d instead!\n" TERM_NORM,
|
||||
options.chain_length);
|
||||
fprintf(stderr, "-c is a deprecated option. "
|
||||
"Please use --led-chain=... instead!\n");
|
||||
any_deprecated_option = true;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
fprintf(stderr, "-p is a deprecated option. "
|
||||
"Please use --led-pwm-bits=... instead!\n");
|
||||
any_deprecated_option = true;
|
||||
break;
|
||||
case 'b':
|
||||
fprintf(stderr, "-b is a deprecated option. "
|
||||
"Please use --led-brightness=... instead!\n");
|
||||
any_deprecated_option = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -214,56 +199,19 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
std::string err;
|
||||
if (!options.Validate(&err)) {
|
||||
fprintf(stderr, "%s", err.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (brightness < 1 || brightness > 100) {
|
||||
fprintf(stderr, "Brightness is outside usable range.\n");
|
||||
if (any_deprecated_option)
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "Expected image filename.\n");
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
if (matrix == NULL)
|
||||
return 1;
|
||||
|
||||
const char *filename = argv[optind];
|
||||
|
||||
/*
|
||||
* Set up GPIO pins. This fails when not running as root.
|
||||
*/
|
||||
GPIO io;
|
||||
if (!io.Init())
|
||||
return 1;
|
||||
|
||||
// Start daemon before we start any threads.
|
||||
if (as_daemon) {
|
||||
if (fork() != 0)
|
||||
return 0;
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
}
|
||||
|
||||
RGBMatrix *const matrix = new RGBMatrix(&io, options);
|
||||
if (pwm_bits >= 0 && !matrix->SetPWMBits(pwm_bits)) {
|
||||
fprintf(stderr, "Invalid range of pwm-bits\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
matrix->SetBrightness(brightness);
|
||||
|
||||
// Here is an example where to add your own transformer. In this case, we
|
||||
// just to the chain-of-four-32x32 => 64x64 transformer, but just use any
|
||||
// of the transformers in transformer.h or write your own.
|
||||
if (large_display) {
|
||||
// Mapping the coordinates of a 32x128 display mapped to a square of 64x64
|
||||
matrix->SetTransformer(new rgb_matrix::LargeSquare64x64Transformer());
|
||||
}
|
||||
|
||||
std::vector<Magick::Image> sequence_pics;
|
||||
if (!LoadAnimation(filename, matrix->width(), matrix->height(),
|
||||
&sequence_pics)) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue