diff --git a/src/internal/methods/NeoEsp32RmtMethod.h b/src/internal/methods/NeoEsp32RmtMethod.h index 5c27b1a..67cadbf 100644 --- a/src/internal/methods/NeoEsp32RmtMethod.h +++ b/src/internal/methods/NeoEsp32RmtMethod.h @@ -565,15 +565,17 @@ public: typedef NeoNoSettings SettingsObject; NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : - _sizeData(pixelCount * elementSize + settingsSize), - _pin(pin) + _pin(pin), + _sizeData(pixelCount* elementSize + settingsSize), + _pixelCount(pixelCount) { construct(); } NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) : - _sizeData(pixelCount* elementSize + settingsSize), _pin(pin), + _sizeData(pixelCount* elementSize + settingsSize), + _pixelCount(pixelCount), _channel(channel) { construct(); @@ -590,7 +592,6 @@ public: gpio_matrix_out(_pin, SIG_GPIO_OUT_IDX, false, false); pinMode(_pin, INPUT); - free(_dataEditing); free(_dataSending); } @@ -623,67 +624,93 @@ public: ESP_ERROR_CHECK(rmt_translator_init(_channel.RmtChannelNumber, T_SPEED::Translate)); } - void Update(bool maintainBufferConsistency) + template + void Update( + T_COLOR_OBJECT* pixels, + size_t countPixels, + const typename T_COLOR_FEATURE::SettingsObject& featureSettings, + const T_SHADER& shader) { // wait for not actively sending data // this will time out at 10 seconds, an arbitrarily long period of time // and do nothing if this happens if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS))) { - // now start the RMT transmit with the editing buffer before we swap - ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_write_sample(_channel.RmtChannelNumber, _dataEditing, _sizeData, false)); + // fill buffer + const size_t sendDataSize = T_COLOR_FEATURE::SettingsSize >= T_COLOR_FEATURE::PixelSize ? T_COLOR_FEATURE::SettingsSize : T_COLOR_FEATURE::PixelSize; + uint8_t sendData[sendDataSize]; + uint8_t* data = _dataSending; - if (maintainBufferConsistency) + // if there are settings at the front + if (T_COLOR_FEATURE::applyFrontSettings(sendData, sendDataSize, featureSettings)) { - // copy editing to sending, - // this maintains the contract that "colors present before will - // be the same after", otherwise GetPixelColor will be inconsistent - memcpy(_dataSending, _dataEditing, _sizeData); + FillBuffer(sendData, T_COLOR_FEATURE::SettingsSize, &data); } - // swap so the user can modify without affecting the async operation - std::swap(_dataSending, _dataEditing); + // fill primary color data + T_COLOR_OBJECT* pixel = pixels; + const T_COLOR_OBJECT* pixelEnd = pixel + countPixels; + uint16_t stripCount = _pixelCount; + + while (stripCount--) + { + typename T_COLOR_FEATURE::ColorObject color = shader.Apply(*pixel); + T_COLOR_FEATURE::applyPixelColor(sendData, sendDataSize, color); + + FillBuffer(sendData, T_COLOR_FEATURE::PixelSize, &data); + + pixel++; + if (pixel >= pixelEnd) + { + // restart at first + pixel = pixels; + } + } + + + // if there are settings at the back + if (T_COLOR_FEATURE::applyBackSettings(sendData, sendDataSize, featureSettings)) + { + FillBuffer(sendData, T_COLOR_FEATURE::SettingsSize, &data); + } + + // now start the RMT transmit with the editing buffer before we swap + ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_write_sample(_channel.RmtChannelNumber, _dataSending, _sizeData, false)); } } - bool AlwaysUpdate() - { - // this method requires update to be called only if changes to buffer - return false; - } - - uint8_t* getData() const - { - return _dataEditing; - }; - - size_t getDataSize() const - { - return _sizeData; - } - void applySettings([[maybe_unused]] const SettingsObject& settings) { } private: - const size_t _sizeData; // Size of '_data*' buffers const uint8_t _pin; // output pin number + const uint16_t _pixelCount; // count of pixels in the strip + const size_t _sizeData; // Size of '_data*' buffers + const T_CHANNEL _channel; // holds instance for multi channel support // Holds data stream which include LED color values and other settings as needed - uint8_t* _dataEditing; // exposed for get and set uint8_t* _dataSending; // used for async send using RMT void construct() { - _dataEditing = static_cast(malloc(_sizeData)); - // data cleared later in Begin() - _dataSending = static_cast(malloc(_sizeData)); // no need to initialize it, it gets overwritten on every send } + + void FillBuffer(const uint8_t* sendData, size_t sendDataSize, uint8_t** buffer) + { + const uint8_t* pEnd = sendData + sendDataSize; + + while (sendData < pEnd) + { + *(*buffer)++ = *sendData++; + } + } }; // normal