Move dmx_input into its own task on core 0.

This was necessary because otherwise it is not able to respond to rdm in time.
This commit is contained in:
Arne 2023-08-25 20:59:46 +02:00 committed by Will Tatam
parent 68e9d701de
commit 8f398dfd08
2 changed files with 103 additions and 38 deletions

View File

@ -28,6 +28,7 @@ void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
USER_PRINTF("DMX personality changed to to: %d\n", DMXMode);
}
}
void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
void *context)
{
@ -48,9 +49,8 @@ void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
}
}
dmx_config_t DMXInput::createConfig() const
static dmx_config_t createConfig()
{
dmx_config_t config;
config.pd_size = 255;
config.dmx_start_address = DMXAddress; // TODO split between input and output address
@ -91,9 +91,55 @@ dmx_config_t DMXInput::createConfig() const
return config;
}
void dmxReceiverTask(void *context)
{
DMXInput *instance = static_cast<DMXInput *>(context);
if (instance == nullptr)
{
return;
}
if (instance->installDriver())
{
while (true)
{
instance->updateInternal();
}
}
}
bool DMXInput::installDriver()
{
const auto config = createConfig();
if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT))
{
USER_PRINTF("Error: Failed to install dmx driver\n");
return false;
}
USER_PRINTF("Listening for DMX on pin %u\n", rxPin);
USER_PRINTF("Sending DMX on pin %u\n", txPin);
USER_PRINTF("DMX enable pin is: %u\n", enPin);
dmx_set_pin(inputPortNum, txPin, rxPin, enPin);
rdm_register_dmx_start_address(inputPortNum, rdmAddressChangedCb, this);
rdm_register_dmx_personality(inputPortNum, rdmPersonalityChangedCb, this);
initialized = true;
return true;
}
void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPortNum)
{
#ifdef WLED_ENABLE_DMX_OUTPUT
if(inputPortNum == dmxOutputPort)
{
USER_PRINTF("DMXInput: Error: Input port == output port");
return;
}
#endif
if (inputPortNum < 3 && inputPortNum > 0)
{
this->inputPortNum = inputPortNum;
@ -121,21 +167,17 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo
return;
}
const auto config = createConfig();
if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT))
this->rxPin = rxPin;
this->txPin = txPin;
this->enPin = enPin;
// put dmx receiver into seperate task because it should not be blocked
// pin to core 0 because wled is running on core 1
xTaskCreatePinnedToCore(dmxReceiverTask, "DMX_RCV_TASK", 10240, this, 2, &task, 0);
if (!task)
{
USER_PRINTF("Error: Failed to install dmx driver\n");
return;
USER_PRINTF("Error: Failed to create dmx rcv task");
}
USER_PRINTF("Listening for DMX on pin %u\n", rxPin);
USER_PRINTF("Sending DMX on pin %u\n", txPin);
USER_PRINTF("DMX enable pin is: %u\n", enPin);
dmx_set_pin(inputPortNum, txPin, rxPin, enPin);
rdm_register_dmx_start_address(inputPortNum, rdmAddressChangedCb, this);
rdm_register_dmx_personality(inputPortNum, rdmPersonalityChangedCb, this);
initialized = true;
}
else
{
@ -144,7 +186,7 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo
}
}
void DMXInput::update()
void DMXInput::updateInternal()
{
if (!initialized)
{
@ -153,45 +195,43 @@ void DMXInput::update()
checkAndUpdateConfig();
byte dmxdata[DMX_PACKET_SIZE];
dmx_packet_t packet;
unsigned long now = millis();
if (dmx_receive(inputPortNum, &packet, 0))
if (dmx_receive(inputPortNum, &packet, DMX_TIMEOUT_TICK))
{
if (!packet.err)
{
if (!connected)
{
USER_PRINTLN("DMX is connected!");
connected = true;
}
else if (!packet.is_rdm)
connected = true;
identify = isIdentifyOn();
if (!packet.is_rdm)
{
const std::lock_guard<std::mutex> lock(dmxDataLock);
dmx_read(inputPortNum, dmxdata, packet.size);
handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0);
}
lastUpdate = now;
}
else
{
/*This can happen when you first connect or disconnect your DMX devices.
If you are consistently getting DMX errors, then something may have gone wrong. */
DEBUG_PRINT("A DMX error occurred - ");
DEBUG_PRINTLN(packet.err); // TODO translate err code to string for output
connected = false;
}
}
else if (connected && (now - lastUpdate > 5000))
else
{
connected = false;
USER_PRINTLN("DMX was disconnected.");
}
}
if (isIdentifyOn())
void DMXInput::update()
{
if (identify)
{
DEBUG_PRINTLN("RDM Identify active");
turnOnAllLeds();
}
else if (connected)
{
const std::lock_guard<std::mutex> lock(dmxDataLock);
handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0);
}
}
void DMXInput::turnOnAllLeds()

View File

@ -1,6 +1,9 @@
#pragma once
#include <cstdint>
#include <esp_dmx.h>
#include <atomic>
#include <mutex>
/*
* Support for DMX/RDM input via serial (e.g. max485) on ESP32
* ESP32 Library from:
@ -28,7 +31,12 @@ private:
/// overrides everything and turns on all leds
void turnOnAllLeds();
dmx_config_t createConfig() const;
/// installs the dmx driver
/// @return false on fail
bool installDriver();
/// is called by the dmx receive task regularly to receive new dmx data
void updateInternal();
// is invoked whenver the dmx start address is changed via rdm
friend void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
@ -38,11 +46,28 @@ private:
friend void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
void *context);
uint8_t inputPortNum = 255; // TODO make this configurable
/// The internal dmx task.
/// This is the main loop of the dmx receiver. It never returns.
friend void dmxReceiverTask(void * context);
uint8_t inputPortNum = 255;
uint8_t rxPin = 255;
uint8_t txPin = 255;
uint8_t enPin = 255;
/// is written to by the dmx receive task.
byte dmxdata[DMX_PACKET_SIZE]; //TODO add locking somehow? maybe double buffer?
/// True once the dmx input has been initialized successfully
bool initialized = false; // true once init finished successfully
/// True if dmx is currently connected
bool connected = false;
std::atomic<bool> connected{false};
std::atomic<bool> identify{false};
/// Timestamp of the last time a dmx frame was received
unsigned long lastUpdate = 0;
/// Taskhandle of the dmx task that is running in the background
TaskHandle_t task;
/// Guards access to dmxData
std::mutex dmxDataLock;
};