kopia lustrzana https://github.com/Aircoookie/WLED
				
				
				
			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.pull/4495/head
							rodzic
							
								
									68e9d701de
								
							
						
					
					
						commit
						8f398dfd08
					
				| 
						 | 
				
			
			@ -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;
 | 
			
		||||
  
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue