beyondscreen / node-rpi-ws281x-native

native bindings to drive WS2811 (or WS2812) LED-Controllers on a Raspberry Pi
MIT License
224 stars 101 forks source link

Initialize with different options #113

Open gbkwiatt opened 3 years ago

gbkwiatt commented 3 years ago

I am having difficulties trying to make it work. I used C library previously with settings for my stripe:

#define LED_PIN 19 //#GPIO pin connected to the pixels(18 uses PWM !).
//LED_PIN         10      // # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
#define LED_FREQ_HZ 800000 //#LED signal frequency in hertz(usually 800khz)
#define LED_DMA 10         // # DMA channel to use for generating signal (try 10)
#define LED_BRIGHTNESS 255 // # Set to 0 for darkest and 255 for brightest
#define LED_INVERT 0       //True to invert the signal(when using NPN transistor level shift)
#define LED_CHANNEL 1      // # set to '1' for GPIOs 13, 19, 41, 45 or 53

That was working fine in Cpp

No I am trying to convert that to this library but I can't make it to work. I can't test it on default gpio 18 because I broke it ;)

how do you properly set it up ? Tried that:

const options = {
        dma: config.leds.dma,
        freq: config.leds.freq,
        channels: [
            { count: 20, gpio: 19, invert: false, brightness: 255, stripType: 'ws2812' },
            { count: 20, gpio: 19, invert: false, brightness: 128, stripType: 'ws2812' }
        ]
    };

and that:

const options = {
        dma: config.leds.dma,
        freq: config.leds.freq,
        gpio: 19,//config.leds.gpio,
        invert: config.leds.invert,
        brightness: config.leds.brightness,
        stripType: 'ws2812'
    };
gbkwiatt commented 3 years ago

OK I've made v1.x work with node14.

Had to update "nan": "^2.14.2", to the latest in package.json

And because some functions are deprecated I had to modify rpi-ws281x.cc as below. Then npm install works, and I was amble to initilize LEDs like this (and use channel 1 for GPIO 19):

 const options = {
        dma: config.leds.dma,
        freq: config.leds.freq,
        channels: [
            { count: 20, gpio: 18, invert: false, brightness: 255, stripType: ws281x.stripType.WS2812 },
            { count: 20, gpio: 19, invert: false, brightness: 255, stripType: ws281x.stripType.WS2812 }
        ],
    };
    // ---- trap the SIGINT and reset before exit
    process.on('SIGINT', function () {
        ws281x.reset();
        log.debug("Reseting Leds on exit...")
        process.nextTick(function () { process.exit(0); });
    });
    const channel = ws281x.init(options);
// Rainbow test on channel 1
    var offset = 0;
    setInterval(function () {
        for (var i = 0; i < 20; i++) {
          channel[1].array[i] = colorwheel((offset + i) % 256);
        }
        offset = (offset + 1) % 256;

        ws281x.render();
      }, 1000 / 30);
//rpi-ws281x.cc
#include <nan.h>

#include <v8.h>

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include <algorithm>

extern "C" {
#include "rpi_ws281x/ws2811.h"
}

using namespace v8;

#define DEFAULT_TARGET_FREQ 800000
#define DEFAULT_GPIO_PIN 18
#define DEFAULT_DMANUM 10

#define PARAM_FREQ 1
#define PARAM_DMANUM 2
#define PARAM_GPIONUM 3
#define PARAM_COUNT 4
#define PARAM_INVERT 5
#define PARAM_BRIGHTNESS 6
#define PARAM_STRIP_TYPE 7

ws2811_t ws281x;

/**
 * ws281x.setParam(param:Number, value:Number)
 * wrap setting global params in ws2811_t
 */
void setParam(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  if (info.Length() != 2)
  {
    Nan::ThrowTypeError("setParam(): expected two params");
    return;
  }

  if (!info[0]->IsNumber())
  {
    Nan::ThrowTypeError("setParam(): expected argument 1 to be the parameter-id");
    return;
  }

  if (!info[1]->IsNumber())
  {
    Nan::ThrowTypeError("setParam(): expected argument 2 to be the value");
    return;
  }

  const int param = Nan::To<int32_t>(info[0]).FromJust();
  const int value = Nan::To<int32_t>(info[1]).FromJust();

  switch (param)
  {
  case PARAM_FREQ:
    ws281x.freq = value;
    break;
  case PARAM_DMANUM:
    ws281x.dmanum = value;
    break;

  default:
    Nan::ThrowTypeError("setParam(): invalid parameter-id");
    return;
  }
}
/**
 * ws281x.setChannelParam(channel:Number, param:Number, value:Number)
 *
 * wrap setting params in ws2811_channel_t
 */
void setChannelParam(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  if (info.Length() != 3)
  {
    Nan::ThrowTypeError("setChannelParam(): missing argument");
    return;
  }

  // retrieve channelNumber from argument 1
  if (!info[0]->IsNumber())
  {
    Nan::ThrowTypeError("setChannelParam(): expected argument 1 to be the channel-number");
    return;
  }

  const int channelNumber = Nan::To<int32_t>(info[0]).FromJust();
  if (channelNumber > 1 || channelNumber < 0)
  {
    Nan::ThrowError("setChannelParam(): invalid chanel-number");
    return;
  }

  if (!info[1]->IsNumber())
  {
    Nan::ThrowTypeError("setChannelParam(): expected argument 2 to be the parameter-id");
    return;
  }

  if (!info[2]->IsNumber() && !info[2]->IsBoolean())
  {
    Nan::ThrowTypeError("setChannelParam(): expected argument 3 to be the value");
    return;
  }

  ws2811_channel_t* channel = &ws281x.channel[channelNumber];
  const int param = Nan::To<int32_t>(info[1]).FromJust();
  const int value = Nan::To<int32_t>(info[2]).FromJust();

  switch (param)
  {
  case PARAM_GPIONUM:
    channel->gpionum = value;
    break;
  case PARAM_COUNT:
    channel->count = value;
    break;
  case PARAM_INVERT:
    channel->invert = value;
    break;
  case PARAM_BRIGHTNESS:
    channel->brightness = (uint8_t)value;
    break;
  case PARAM_STRIP_TYPE:
    channel->strip_type = value;
    break;

  default:
    Nan::ThrowTypeError("setChannelParam(): invalid parameter-id");
    return;
  }
}

/**
 * ws281x.setChannelData(channel:Number, buffer:Buffer)
 *
 * wrap copying data to ws2811_channel_t.leds
 */
void setChannelData(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  if (info.Length() != 2)
  {
    Nan::ThrowTypeError("setChannelData(): missing argument.");
    return;
  }

  // retrieve channelNumber from argument 1
  if (!info[0]->IsNumber())
  {
    Nan::ThrowTypeError("setChannelData(): expected argument 1 to be the channel-number.");
    return;
  }

  int channelNumber = Nan::To<int32_t>(info[0]).FromJust();
  if (channelNumber > 1 || channelNumber < 0)
  {
    Nan::ThrowError("setChannelData(): invalid chanel-number");
    return;
  }
  ws2811_channel_t channel = ws281x.channel[channelNumber];

  // retrieve buffer from argument 2
  if (!node::Buffer::HasInstance(info[1]))
  {
    Nan::ThrowTypeError("setChannelData(): expected argument 2 to be a Buffer");
    return;
  }
  v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
  auto buffer = info[1]->ToObject(context).ToLocalChecked();
  uint32_t *data = (uint32_t *)node::Buffer::Data(buffer);

  if (channel.count == 0 || channel.leds == NULL)
  {
    Nan::ThrowError("setChannelData(): channel not ready");
    return;
  }

  const int numBytes = std::min(
      node::Buffer::Length(buffer),
      sizeof(ws2811_led_t) * ws281x.channel[0].count);

  // FIXME: handle memcpy-result
  memcpy(channel.leds, data, numBytes);
}

/**
 * ws281x.init()
 *
 * wrap ws2811_init()
 */
void init(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  ws2811_return_t ret;

  ret = ws2811_init(&ws281x);
  if (ret != WS2811_SUCCESS)
  {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }
}

/**
 * ws281x.render()
 *
 * wrap ws2811_wait() and ws2811_render()
 */
void render(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  ws2811_return_t ret;

  ret = ws2811_wait(&ws281x);
  if (ret != WS2811_SUCCESS)
  {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }

  ret = ws2811_render(&ws281x);
  if (ret != WS2811_SUCCESS)
  {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }
}

/**
 * ws281x.finalize()
 *
 * wrap ws2811_wait() and ws2811_fini()
 */
void finalize(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  ws2811_return_t ret;

  ret = ws2811_wait(&ws281x);
  if (ret != WS2811_SUCCESS)
  {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }

  ws2811_fini(&ws281x);
}

/**
 * initializes the module.
 */
void initialize(Local<Object> exports)
{
  ws281x.freq = DEFAULT_TARGET_FREQ;
  ws281x.dmanum = DEFAULT_DMANUM;

  NAN_EXPORT(exports, setParam);
  NAN_EXPORT(exports, setChannelParam);
  NAN_EXPORT(exports, setChannelData);
  NAN_EXPORT(exports, init);
  NAN_EXPORT(exports, render);
  NAN_EXPORT(exports, finalize);
}

NODE_MODULE(rpi_ws281x, initialize)

// vi: ts=2 sw=2 expandtab
ngrealish commented 1 year ago

I am trying 19 on channel 1 with no results unfortunately. I've used your update to the rpi-ws281x.cc with no success. Any other hints or thoughts on this one? I cannot use 13. 18 is working for me, so I'd like to use 19 as a second set.