Skip to content

Commit

Permalink
Add support for led refresh rate limiting option
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeden committed Apr 4, 2022
1 parent 2611359 commit 8518072
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 68 deletions.
12 changes: 10 additions & 2 deletions examples/_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,32 @@ import {
LedMatrix,
// LedMatrixUtils,
MatrixOptions,
RuntimeFlag,
// PixelMapperType,
RuntimeOptions,
} from '../src';

export const matrixOptions: MatrixOptions = {
...LedMatrix.defaultMatrixOptions(),
rows: 32,
rows: 64,
cols: 64,
chainLength: 2,
hardwareMapping: GpioMapping.Regular,
parallel: 1,
parallel: 2,
// limitRefreshRateHz: 1,
showRefreshRate: true,
// pixelMapperConfig: LedMatrixUtils.encodeMappers(
// { type: PixelMapperType.Chainlink }
// ),
// pixelMapperConfig: LedMatrixUtils.encodeMappers({ type: PixelMapperType.U }),
};

console.log('matrix options: ', JSON.stringify(matrixOptions, null, 2));

export const runtimeOptions: RuntimeOptions = {
...LedMatrix.defaultRuntimeOptions(),
gpioSlowdown: 4,
dropPrivileges: RuntimeFlag.Off,
};

console.log('runtime options: ', JSON.stringify(runtimeOptions, null, 2));
2 changes: 1 addition & 1 deletion nodemon.build.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"ext": "ts,json,cc,h,gyp",
"exec": "npm run quick-build && npm run example -- examples/kitchen-sink.ts",
"exec": "npm run quick-build && sudo npm run example -- examples/kitchen-sink.ts",
"restartable": true,
"events": {},
"watch": [
Expand Down
119 changes: 54 additions & 65 deletions src/led-matrix.addon.cc
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
#include "led-matrix.addon.h"

#define BILLION 1000000000L;
#define MILLION 1000000000L;
#define BILLION 1000000000L;
#define MILLION 1000000000L;

inline double get_now_ms() {
struct timespec t;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &t) < 0) {
throw "Failed to get the current time.";
}
if (clock_gettime(CLOCK_MONOTONIC_RAW, &t) < 0) { throw "Failed to get the current time."; }

return (t.tv_sec * 1000) + (t.tv_nsec / 1000000);
}
Expand Down Expand Up @@ -71,7 +69,7 @@ LedMatrixAddon::LedMatrixAddon(const Napi::CallbackInfo& info)
if (!info[1].IsObject()) {
throw Napi::Error::New(env, "Constructor expects its first parameter to be an object of runtime options!");
}
auto matrixOpts = create_matrix_options(env, info[0].As<Napi::Object>());
auto matrixOpts = create_matrix_options(env, info[0].As<Napi::Object>());
auto runtimeOpts = create_runtime_options(env, info[1].As<Napi::Object>());

this->matrix_ = CreateMatrixFromOptions(matrixOpts, runtimeOpts);
Expand All @@ -98,20 +96,16 @@ Napi::Value LedMatrixAddon::sync(const Napi::CallbackInfo& info) {
auto env = info.Env();

if (!after_sync_cb_.IsEmpty()) {
auto now = get_now_ms();
auto now_ms = now - t_start_;
t_dsync_ms_ = now_ms - t_sync_ms_;
t_sync_ms_ = now_ms;

auto resync = after_sync_cb_.Call(info.This(), {
info.This(),
Napi::Number::New(env, t_dsync_ms_),
Napi::Number::New(env, t_sync_ms_)
});

if (resync.ToBoolean() == true) {
sync(info);
}
auto now = get_now_ms();
auto now_ms = now - t_start_;
t_dsync_ms_ = now_ms - t_sync_ms_;
t_sync_ms_ = now_ms;

auto resync
= after_sync_cb_
.Call(info.This(), { info.This(), Napi::Number::New(env, t_dsync_ms_), Napi::Number::New(env, t_sync_ms_) });

if (resync.ToBoolean() == true) { sync(info); }
}

return Napi::Number::New(env, 0);
Expand All @@ -133,35 +127,32 @@ Napi::Value LedMatrixAddon::map(const Napi::CallbackInfo& info) {

assert(cb.IsFunction());

auto env = info.Env();
auto now = get_now_ms();
auto env = info.Env();
auto now = get_now_ms();
auto now_ms = Napi::Number::New(env, now - t_start_);

Napi::Array coord_array = Napi::Array::New(env, 3);
uint32_t zero = 0; // The compiler can't match the overloaded signature if given 0 explicitly
uint32_t one = 1;
uint32_t two = 2;
Napi::Array coord_array = Napi::Array::New(env, 3);
uint32_t zero = 0; // The compiler can't match the overloaded signature if given 0 explicitly
uint32_t one = 1;
uint32_t two = 2;

auto i = 0;
auto i = 0;

for (int x = 0; x < this->matrix_->width(); x++) {
coord_array.Set(zero, x);
for (int x = 0; x < this->matrix_->width(); x++) {
coord_array.Set(zero, x);

for (int y = 0; y < this->matrix_->height(); y++) {
coord_array.Set(one, y);
coord_array.Set(two, i++);
for (int y = 0; y < this->matrix_->height(); y++) {
coord_array.Set(one, y);
coord_array.Set(two, i++);

auto color = cb.Call(info.This(), {
coord_array,
now_ms
});
auto color = cb.Call(info.This(), { coord_array, now_ms });

assert(color.IsNumber());
assert(color.IsNumber());

const auto hex = color.As<Napi::Number>().Uint32Value();
this->matrix_->SetPixel(x, y, 0xFF & (hex >> 16), 0xFF & (hex >> 8), 0xFF & hex);
}
}
const auto hex = color.As<Napi::Number>().Uint32Value();
this->matrix_->SetPixel(x, y, 0xFF & (hex >> 16), 0xFF & (hex >> 8), 0xFF & hex);
}
}

return info.This();
}
Expand All @@ -179,10 +170,10 @@ Napi::Value LedMatrixAddon::brightness(const Napi::CallbackInfo& info) {

Napi::Value LedMatrixAddon::clear(const Napi::CallbackInfo& info) {
if (info.Length() > 0) {
const auto x0 = info[0].As<Napi::Number>().Uint32Value();
const auto y0 = info[1].As<Napi::Number>().Uint32Value();
const auto x1 = info[2].As<Napi::Number>().Uint32Value();
const auto y1 = info[3].As<Napi::Number>().Uint32Value();
const auto x0 = info[0].As<Napi::Number>().Uint32Value();
const auto y0 = info[1].As<Napi::Number>().Uint32Value();
const auto x1 = info[2].As<Napi::Number>().Uint32Value();
const auto y1 = info[3].As<Napi::Number>().Uint32Value();
const auto black = Color(0, 0, 0);
for (auto y = y0; y <= y1; y++) { DrawLine(this->canvas_, x0, y, x1, y, black); }
}
Expand All @@ -196,12 +187,12 @@ Napi::Value LedMatrixAddon::draw_buffer(const Napi::CallbackInfo& info) {
const auto buffer = info[0].As<Napi::Buffer<uint8_t> >();
const auto w = info[1].IsNumber() ? info[1].As<Napi::Number>().Uint32Value() : this->matrix_->width();
const auto h = info[2].IsNumber() ? info[2].As<Napi::Number>().Uint32Value() : this->matrix_->height();
const auto data = buffer.Data();
const auto len = buffer.Length();
const auto data = buffer.Data();
const auto len = buffer.Length();

assert(len == w * h * 3);

Image* img = new Image();
Image* img = new Image();
Pixel* pixels = (Pixel*) malloc(sizeof(Pixel) * w * h);
for (unsigned int i = 0; i < w * h; i++) {
auto j = i * 3;
Expand Down Expand Up @@ -351,9 +342,9 @@ Napi::Value LedMatrixAddon::bg_color(const Napi::CallbackInfo& info) {

Napi::Value LedMatrixAddon::font(const Napi::CallbackInfo& info) {
if (info.Length() > 0) {
auto font = Napi::ObjectWrap<FontAddon>::Unwrap(info[0].As<Napi::Object>());
auto font = Napi::ObjectWrap<FontAddon>::Unwrap(info[0].As<Napi::Object>());
this->font_ = &(font->font);
font_name_ = font->name(info).ToString();
font_name_ = font->name(info).ToString();
return info.This();
}
else {
Expand All @@ -362,18 +353,15 @@ Napi::Value LedMatrixAddon::font(const Napi::CallbackInfo& info) {
}

Napi::Value LedMatrixAddon::get_available_pixel_mappers(const Napi::CallbackInfo& info) {
auto env = info.Env();
auto mappers = GetAvailablePixelMappers();
Napi::Array mapper_name_array = Napi::Array::New(env, mappers.size());
auto env = info.Env();
auto mappers = GetAvailablePixelMappers();
Napi::Array mapper_name_array = Napi::Array::New(env, mappers.size());

for (uint8_t i = 0; i < mappers.size(); i++) {
mapper_name_array.Set(i, Napi::String::New(env, mappers.at(i)));
}
for (uint8_t i = 0; i < mappers.size(); i++) { mapper_name_array.Set(i, Napi::String::New(env, mappers.at(i))); }

return mapper_name_array;
return mapper_name_array;
}


/**
* Create an instance of Options from a JS object.
*/
Expand All @@ -389,6 +377,7 @@ RGBMatrix::Options LedMatrixAddon::create_matrix_options(const Napi::Env& env, c
options.inverse_colors = obj.Get("inverseColors").As<Napi::Boolean>();
auto led_rgb_sequence = std::string(obj.Get("ledRgbSequence").As<Napi::String>());
options.led_rgb_sequence = strcpy(new char[led_rgb_sequence.size()], led_rgb_sequence.c_str());
options.limit_refresh_rate_hz = obj.Get("limitRefreshRateHz").As<Napi::Number>();
auto pixel_mapper_config = std::string(obj.Get("pixelMapperConfig").As<Napi::String>());
options.pixel_mapper_config = strcpy(new char[pixel_mapper_config.size()], pixel_mapper_config.c_str());
options.multiplexing = obj.Get("multiplexing").As<Napi::Number>();
Expand All @@ -413,7 +402,7 @@ RGBMatrix::Options LedMatrixAddon::create_matrix_options(const Napi::Env& env, c
RuntimeOptions LedMatrixAddon::create_runtime_options(const Napi::Env& env, const Napi::Object& obj) {
RuntimeOptions options = RuntimeOptions();

options.gpio_slowdown = obj.Get("gpioSlowdown").As<Napi::Number>();
options.gpio_slowdown = obj.Get("gpioSlowdown").As<Napi::Number>();
options.daemon = obj.Get("daemon").As<Napi::Number>();
options.drop_privileges = obj.Get("dropPrivileges").As<Napi::Number>();
options.do_gpio_init = obj.Get("doGpioInit").As<Napi::Boolean>();
Expand Down Expand Up @@ -441,6 +430,7 @@ Napi::Object LedMatrixAddon::matrix_options_to_obj(const Napi::Env& env, const R
obj.Set("hardwareMapping", Napi::String::New(env, hardware_mapping));
obj.Set("inverseColors", Napi::Boolean::New(env, options.inverse_colors));
obj.Set("ledRgbSequence", Napi::String::New(env, led_rgb_sequence));
obj.Set("limitRefreshRateHz", Napi::Number::New(env, options.limit_refresh_rate_hz));
obj.Set("multiplexing", Napi::Number::New(env, options.multiplexing));
obj.Set("parallel", Napi::Number::New(env, options.parallel));
obj.Set("pixelMapperConfig", Napi::String::New(env, pixel_mapper_config));
Expand All @@ -460,11 +450,10 @@ Napi::Object LedMatrixAddon::matrix_options_to_obj(const Napi::Env& env, const R
*/
Napi::Object LedMatrixAddon::runtime_options_to_obj(const Napi::Env& env, const RuntimeOptions& options) {
auto obj = Napi::Object::New(env);

obj.Set("gpioSlowdown", Napi::Number::New(env, options.gpio_slowdown));
obj.Set("daemon", Napi::Number::New(env, options.daemon));
obj.Set("dropPrivileges", Napi::Number::New(env, options.drop_privileges));
obj.Set("doGpioInit", Napi::Boolean::New(env, options.do_gpio_init));
obj.Set("dropPrivileges", Napi::Number::New(env, options.drop_privileges));
obj.Set("gpioSlowdown", Napi::Number::New(env, options.gpio_slowdown));

return obj;
}
Expand Down Expand Up @@ -498,9 +487,9 @@ Color LedMatrixAddon::color_from_callback_info(const Napi::CallbackInfo& info) {
}
else if (info[0].IsObject()) {
const auto obj = info[0].As<Napi::Object>();
uint8_t r = obj.Get("r").As<Napi::Number>().Uint32Value();
uint8_t g = obj.Get("g").As<Napi::Number>().Uint32Value();
uint8_t b = obj.Get("b").As<Napi::Number>().Uint32Value();
uint8_t r = obj.Get("r").As<Napi::Number>().Uint32Value();
uint8_t g = obj.Get("g").As<Napi::Number>().Uint32Value();
uint8_t b = obj.Get("b").As<Napi::Number>().Uint32Value();
return Color(r, g, b);
}
else if (info[0].IsNumber()) {
Expand Down
34 changes: 34 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,39 @@ export enum RowAddressType {
}

export enum GpioMapping {
/**
* The regular hardware mapping described in the wiring.md and used
* by the adapter PCBs.
*/
Regular = 'regular',

/**
* This is used if you have an Adafruit HAT in the default configuration
*/
AdafruitHat = 'adafruit-hat',

/**
* An Adafruit HAT with the PWM modification
*/
AdafruitHatPwm = 'adafruit-hat-pwm',

/**
* The regular pin-out, but for Raspberry Pi1. The very first Pi1 Rev1 uses
* the same pin for GPIO-21 as later Pis use GPIO-27. Make it work for both.
*/
RegularPi1 = 'regular-pi1',

/**
* Classic: Early forms of this library had this as default mapping, mostly
* derived from the 26 GPIO-header version so that it also can work
* on 40 Pin GPIO headers with more parallel chains.
* Not used anymore.
*/
Classic = 'classic',

/**
* Classic pin-out for Rev-A Raspberry Pi.
*/
ClassicPi1 = 'classic-pi1',
}

Expand Down Expand Up @@ -132,6 +160,12 @@ export interface MatrixOptions {
*/
ledRgbSequence: 'RGB' | 'BGR' | 'BRG' | 'RBG' | 'GRB' | 'GBR';

/**
* Limit refresh rate of LED panel. This will help on a loaded system
* to keep a constant refresh rate. <= 0 for no limit.
*/
limitRefreshRateHz: number;

/**
* @default MuxType.Direct
*/
Expand Down

0 comments on commit 8518072

Please sign in to comment.