Skip to content

Commit

Permalink
Split up PixelDriver in multiple classes
Browse files Browse the repository at this point in the history
  • Loading branch information
niliha committed Jul 26, 2023
1 parent 1d4b064 commit a545bb4
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 232 deletions.
67 changes: 67 additions & 0 deletions src/ArtnetHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "ArtnetHandler.hpp"

ArtnetHandler::ArtnetHandler(BlockingRingBuffer<std::vector<CRGB>> &frameQueue, int pixelCount, int baudrate)
: frameQueue_(frameQueue), artnetSerial_(baudrate), PIXEL_COUNT_(pixelCount), artnetFrame_(pixelCount),
UNIVERSE_COUNT_(std::ceil((pixelCount * 3) / static_cast<float>(512))) {
// The watchdog on core 0 is not reset anymore, since the idle task is not resumed.
// It is disabled to avoid watchdog timeouts (resulting in a reboot).
disableCore0WDT();

// Improves UDP throughput drastically
WiFi.setSleep(false);

setArtnetCallback();
artnetWifi_.begin();
}

void ArtnetHandler::read() {
// This calls onDmxFrame() whenever a ArtDMX packet is received
artnetWifi_.read();
artnetSerial_.read();
}

void ArtnetHandler::setArtnetCallback() {
artnetWifi_.setArtDmxFunc([this](uint16_t universeIndex, uint16_t length, uint8_t sequence, uint8_t *data) {
this->onDmxFrame(universeIndex, length, sequence, data);
});
artnetSerial_.setArtDmxCallback([this](uint16_t universeIndex, uint16_t length, uint8_t sequence, uint8_t *data) {
this->onDmxFrame(universeIndex, length, sequence, data);
});
}

void ArtnetHandler::onDmxFrame(uint16_t universeIndex, uint16_t length, uint8_t sequence, uint8_t *data) {
if (universeIndex >= UNIVERSE_COUNT_) {
return;
}

// Store which universe has got in
receivedUniverses_.insert(universeIndex);

// Read universe and put into the right part of the display buffer
for (unsigned channelIndex = 0; channelIndex < length; channelIndex++) {
setChannel(universeIndex, channelIndex, data[channelIndex]);
}

// All data for this frame has been received
if (receivedUniverses_.size() == UNIVERSE_COUNT_) {
// Reset information about received universes
receivedUniverses_.clear();

// Put the filled frame into the queue such that the FasLED task can consume it
frameQueue_.push(std::move(artnetFrame_));

// Create a new vector for the next frame.
artnetFrame_ = std::vector<CRGB>(PIXEL_COUNT_);
}
}

void ArtnetHandler::setChannel(uint16_t universeIndex, int channelIndex, uint8_t value) {
// integer division will round off to nearest neighbor;
unsigned pixelIndex = (universeIndex * 512 + channelIndex) / 3;
// 0 -> first channel, 1 -> second channel, 2 -> third channel
unsigned rgbChannelIndex = (universeIndex * 512 + channelIndex) % 3;
if (pixelIndex >= PIXEL_COUNT_) {
return;
}
artnetFrame_[pixelIndex][rgbChannelIndex] = value;
}
30 changes: 30 additions & 0 deletions src/ArtnetHandler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <ArtnetWifi.h>
#include <FastLED.h>
#include <set>
#include <vector>

#include "ArtnetSerial.hpp"
#include "BlockingRingBuffer.hpp"

class ArtnetHandler {
public:
ArtnetHandler(BlockingRingBuffer<std::vector<CRGB>> &frameQueue, int pixelCount, int baudrate = 3000000);
void read();

private:
const int PIXEL_COUNT_;
const int UNIVERSE_COUNT_;

BlockingRingBuffer<std::vector<CRGB>> &frameQueue_;
ArtnetWifi artnetWifi_;
ArtnetSerial artnetSerial_;
std::vector<CRGB> artnetFrame_;
std::set<int> receivedUniverses_;

void setChannel(uint16_t universeIndex, int channelIndex, uint8_t value);
void onDmxFrame(uint16_t universeIndex, uint16_t length, uint8_t sequence, uint8_t *data);

void setArtnetCallback();
};
26 changes: 13 additions & 13 deletions src/ArtnetSerial.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ class ArtnetSerial {
void read();

private:
static constexpr int UART2_RX_PIN = 16;
static constexpr int UART2_TX_PIN = 17;
static const int UART2_RX_PIN = 16;
static const int UART2_TX_PIN = 17;

static constexpr char *ARTNET_HEADER = "Art-Net";
static constexpr int ART_DMX_OPCODE = 0x5000;
static constexpr int ART_DMX_MAXIMUM_LENGTH = 530;

static constexpr int ARTNET_OPCODE_LO_OFFSET = 8;
static constexpr int ARTNET_OPCODE_HI_OFFSET = 9;
static constexpr int ART_DMX_SEQUENCE_OFFSET = 12;
static constexpr int ART_DMX_UNIVERSE_LO_OFFSET = 14;
static constexpr int ART_DMX_UNIVERSE_HI_OFFSET = 15;
static constexpr int ART_DMX_LENGTH_HI_OFFSET = 16;
static constexpr int ART_DMX_LENGTH_LO_OFFSET = 17;
static constexpr int ART_DMX_DATA_OFFSET = 18;
static const int ART_DMX_OPCODE = 0x5000;
static const int ART_DMX_MAXIMUM_LENGTH = 530;

static const int ARTNET_OPCODE_LO_OFFSET = 8;
static const int ARTNET_OPCODE_HI_OFFSET = 9;
static const int ART_DMX_SEQUENCE_OFFSET = 12;
static const int ART_DMX_UNIVERSE_LO_OFFSET = 14;
static const int ART_DMX_UNIVERSE_HI_OFFSET = 15;
static const int ART_DMX_LENGTH_HI_OFFSET = 16;
static const int ART_DMX_LENGTH_LO_OFFSET = 17;
static const int ART_DMX_DATA_OFFSET = 18;

enum class State {
START_DETECTION,
Expand Down
32 changes: 17 additions & 15 deletions src/BlockingRingBuffer.hpp
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
#pragma once

#include <condition_variable>
#include <mutex>
#include <deque>
#include <mutex>

template <typename T> class BlockingRingBuffer {

public:
BlockingRingBuffer(size_t capacity) : capacity(capacity) {
BlockingRingBuffer(size_t capacity) : capacity_(capacity) {
}

void push(T &&item) {
{
std::unique_lock<std::mutex> lk(mutex);
if (content.size() == capacity) {
content.pop_front();
std::unique_lock<std::mutex> lock(mutex_);
if (buffer_.size() == capacity_) {
buffer_.pop_front();
}
content.push_back(std::move(item));
buffer_.push_back(std::move(item));
}
not_empty.notify_one();
isNotEmpty_.notify_one();
}

void pop(T &item) {
std::unique_lock<std::mutex> lk(mutex);
not_empty.wait(lk, [this]() { return !content.empty(); });
item = std::move(content.front());
content.pop_front();
std::unique_lock<std::mutex> lock(mutex_);
isNotEmpty_.wait(lock, [this]() { return !buffer_.empty(); });
item = std::move(buffer_.front());
buffer_.pop_front();
}

private:
std::deque<T> content;
size_t capacity;
std::mutex mutex;
std::condition_variable not_empty;
std::deque<T> buffer_;
size_t capacity_;
std::mutex mutex_;
std::condition_variable isNotEmpty_;
};
85 changes: 85 additions & 0 deletions src/FastLedHandler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#pragma once

#define FASTLED_ESP32_I2S // Alternative parallel output driver
#include <FastLED.h>

#include <numeric>
#include <vector>

#include "BlockingRingBuffer.hpp"

template <int PIN_COUNT, const std::array<int, PIN_COUNT> &PINS, EOrder RGB_ORDER = RGB> class FastLedHandler {
public:
FastLedHandler(const std::array<int, PIN_COUNT> &lightsPerPin, int pixelsPerLight = 144)
: PIXELS_PER_LIGHT_(pixelsPerLight),
PIXEL_COUNT_(PIXELS_PER_LIGHT_ * std::accumulate(lightsPerPin.begin(), lightsPerPin.end(), 0))

{
fastLedPixels_.resize(PIXEL_COUNT_);
setupFastled(lightsPerPin);
}

void write(std::vector<CRGB> &frame) {
assert(frame.size() == fastLedPixels_.size());

fastLedPixels_ = frame;
FastLED.show();
}

void testLeds() {
Serial.println("Testing LEDs...");
std::vector<CRGB> colors{CRGB::Red, CRGB::Green, CRGB::Blue};
for (const auto color : colors) {
auto millisBefore = millis();
FastLED.showColor(color);
auto passedMillis = millis() - millisBefore;
Serial.printf("show() took %d ms\n", passedMillis);
delay(500);
FastLED.clear(true);
delay(500);
}
delay(2000);
}

int getPixelCount() {
return PIXEL_COUNT_;
}

private:
// The number of individually addressable pixels per ravelight
const int PIXELS_PER_LIGHT_;
// Total number of pixels across all lights.
const int PIXEL_COUNT_;

// The vector holding color values for each pixel.
// It's size is set in configure() and must not be changed afterwards!
std::vector<CRGB> fastLedPixels_;

void setupFastled(const std::array<int, PIN_COUNT> &lightsPerPin) {
static_assert(PIN_COUNT == 4, "setupFastLed() is hardcoded to handle exactly 4 pins!");
// We can't use a loop here since addLeds() template parameters must be known at
// compile-time
int pixelOffset = 0;
if (lightsPerPin[0] > 0) {
FastLED.addLeds<WS2812, PINS[0], RGB_ORDER>(fastLedPixels_.data(), pixelOffset,
lightsPerPin[0] * PIXELS_PER_LIGHT_);
pixelOffset += lightsPerPin[0] * PIXELS_PER_LIGHT_;
}
if (lightsPerPin[1] > 0) {
FastLED.addLeds<WS2812, PINS[1], RGB_ORDER>(fastLedPixels_.data(), pixelOffset,
lightsPerPin[1] * PIXELS_PER_LIGHT_);
pixelOffset += lightsPerPin[1] * PIXELS_PER_LIGHT_;
}
if (lightsPerPin[2] > 0) {
FastLED.addLeds<WS2812, PINS[2], RGB_ORDER>(fastLedPixels_.data(), pixelOffset,
lightsPerPin[2] * PIXELS_PER_LIGHT_);
pixelOffset += lightsPerPin[2] * PIXELS_PER_LIGHT_;
}
if (lightsPerPin[3] > 0) {
FastLED.addLeds<WS2812, PINS[3], RGB_ORDER>(fastLedPixels_.data(), pixelOffset,
lightsPerPin[3] * PIXELS_PER_LIGHT_);
pixelOffset += lightsPerPin[3] * PIXELS_PER_LIGHT_;
}
FastLED.setCorrection(TypicalLEDStrip);
}
};
Loading

0 comments on commit a545bb4

Please sign in to comment.