-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split up PixelDriver in multiple classes
- Loading branch information
Showing
7 changed files
with
235 additions
and
232 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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_; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
}; |
Oops, something went wrong.