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:
		| @@ -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() | ||||
|   | ||||
| @@ -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; | ||||
|    | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Arne
					Arne