// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- // Example of a clock. This is very similar to the text-example, // except that it shows the time :) // // This code is public domain // (but note, that the led-matrix library this depends on is GPL v2) #include "led-matrix.h" #include "graphics.h" #include #include #include #include #include #include #include #include #include using namespace rgb_matrix; volatile bool interrupt_received = false; static void InterruptHandler(int signo) { interrupt_received = true; } static int usage(const char *progname) { fprintf(stderr, "usage: %s [options]\n", progname); fprintf(stderr, "Reads text from stdin and displays it. " "Empty string: clear screen\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, "\t-d : Default '%%H:%%M'. See strftime()\n" "\t Can be provided multiple times for multiple " "lines\n" "\t-f : Use given font.\n" "\t-x : X-Origin of displaying text (Default: 0)\n" "\t-y : Y-Origin of displaying text (Default: 0)\n" "\t-s : Extra spacing between lines when multiple -d given\n" "\t-S : Extra spacing between letters (Default: 0)\n" "\t-C : Color. Default 255,255,0\n" "\t-B : Background-Color. Default 0,0,0\n" "\t-O : Outline-Color, e.g. to increase contrast.\n" "\n" ); rgb_matrix::PrintMatrixFlags(stderr); return 1; } static bool parseColor(Color *c, const char *str) { return sscanf(str, "%hhu,%hhu,%hhu", &c->r, &c->g, &c->b) == 3; } static bool FullSaturation(const Color &c) { return (c.r == 0 || c.r == 255) && (c.g == 0 || c.g == 255) && (c.b == 0 || c.b == 255); } int main(int argc, char *argv[]) { RGBMatrix::Options matrix_options; rgb_matrix::RuntimeOptions runtime_opt; if (!rgb_matrix::ParseOptionsFromFlags(&argc, &argv, &matrix_options, &runtime_opt)) { return usage(argv[0]); } // We accept multiple format lines std::vector format_lines; Color color(255, 255, 0); Color bg_color(0, 0, 0); Color outline_color(0,0,0); bool with_outline = false; const char *bdf_font_file = NULL; int x_orig = 0; int y_orig = 0; int letter_spacing = 0; int line_spacing = 0; int opt; while ((opt = getopt(argc, argv, "x:y:f:C:B:O:s:S:d:")) != -1) { switch (opt) { case 'd': format_lines.push_back(optarg); break; case 'x': x_orig = atoi(optarg); break; case 'y': y_orig = atoi(optarg); break; case 'f': bdf_font_file = strdup(optarg); break; case 's': line_spacing = atoi(optarg); break; case 'S': letter_spacing = atoi(optarg); break; case 'C': if (!parseColor(&color, optarg)) { fprintf(stderr, "Invalid color spec: %s\n", optarg); return usage(argv[0]); } break; case 'B': if (!parseColor(&bg_color, optarg)) { fprintf(stderr, "Invalid background color spec: %s\n", optarg); return usage(argv[0]); } break; case 'O': if (!parseColor(&outline_color, optarg)) { fprintf(stderr, "Invalid outline color spec: %s\n", optarg); return usage(argv[0]); } with_outline = true; break; default: return usage(argv[0]); } } if (format_lines.empty()) { format_lines.push_back("%H:%M"); } if (bdf_font_file == NULL) { fprintf(stderr, "Need to specify BDF font-file with -f\n"); return usage(argv[0]); } /* * Load font. This needs to be a filename with a bdf bitmap font. */ rgb_matrix::Font font; if (!font.LoadFont(bdf_font_file)) { fprintf(stderr, "Couldn't load font '%s'\n", bdf_font_file); return 1; } rgb_matrix::Font *outline_font = NULL; if (with_outline) { outline_font = font.CreateOutlineFont(); } RGBMatrix *matrix = RGBMatrix::CreateFromOptions(matrix_options, runtime_opt); if (matrix == NULL) return 1; const bool all_extreme_colors = (matrix_options.brightness == 100) && FullSaturation(color) && FullSaturation(bg_color) && FullSaturation(outline_color); if (all_extreme_colors) matrix->SetPWMBits(1); const int x = x_orig; int y = y_orig; FrameCanvas *offscreen = matrix->CreateFrameCanvas(); char text_buffer[256]; struct timespec next_time; next_time.tv_sec = time(NULL); next_time.tv_nsec = 0; struct tm tm; signal(SIGTERM, InterruptHandler); signal(SIGINT, InterruptHandler); while (!interrupt_received) { offscreen->Fill(bg_color.r, bg_color.g, bg_color.b); localtime_r(&next_time.tv_sec, &tm); int line_offset = 0; for (const std::string &line : format_lines) { strftime(text_buffer, sizeof(text_buffer), line.c_str(), &tm); if (outline_font) { rgb_matrix::DrawText(offscreen, *outline_font, x - 1, y + font.baseline() + line_offset, outline_color, NULL, text_buffer, letter_spacing - 2); } rgb_matrix::DrawText(offscreen, font, x, y + font.baseline() + line_offset, color, NULL, text_buffer, letter_spacing); line_offset += font.height() + line_spacing; } // Wait until we're ready to show it. clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &next_time, NULL); // Atomic swap with double buffer offscreen = matrix->SwapOnVSync(offscreen); next_time.tv_sec += 1; } // Finished. Shut down the RGB matrix. delete matrix; write(STDOUT_FILENO, "\n", 1); // Create a fresh new line after ^C on screen return 0; }