 TOD tableOfDevices;                           // UUIDs of found devices
 TOD discoveryTree;                            // stack of UUID ranges for discovery search
 
-UID lower(0,0,0,0,0,0);
-UID upper(0,0,0,0,0,0);
-UID mid(0,0,0,0,0,0);
-UID found(0,0,0,0,0,0);
+UID lower(0, 0, 0, 0, 0, 0);
+UID upper(0, 0, 0, 0, 0, 0);
+UID mid(0, 0, 0, 0, 0, 0);
+UID found(0, 0, 0, 0, 0, 0);
 
 // used to toggle indicator LED on and off
 uint8_t led_state = 0;
 
-/* 
+/*
    utility function to toggle indicator LED on/off
 */
 void blinkLED() {

  }
  artNetInterface->setStatus1Flag(ARTNET_STATUS1_RDM_CAPABLE, 1);
  Serial.print("interfaces created, ");
  
  // if output from network, start wUDP listening for packets
  if ( dmx_direction == OUTPUT_FROM_NETWORK_MODE ) {	
		if ( DMXWiFiConfig.multicastMode() ) {
			if ( DMXWiFiConfig.APMode() ) {
				sUDP.beginMulticast(DMXWiFiConfig.multicastAddress(), sACNInterface->dmxPort());  //WiFi.softAPIP(), 
			} else {
				sUDP.beginMulticast(DMXWiFiConfig.multicastAddress(), sACNInterface->dmxPort());  //WiFi.localIP(), 
			}
		} else {
			sUDP.begin(sACNInterface->dmxPort());
		}
    
    aUDP.begin(artNetInterface->dmxPort());
    artNetInterface->send_art_poll_reply(&aUDP);
	 Serial.print("udp started listening,");
  }

  Serial.println(" setup complete.");
  blinkLED();

  // trial:  Increase loop priority to 2 above DMX, which is 1
  vTaskPrioritySet(xTaskGetCurrentTaskHandle(), 2);
  
} //setup

/************************************************************************

  Copy to output merges slots for Art-Net and sACN on HTP basis
  
*************************************************************************/

void copyDMXToOutput(void) {
	uint8_t a, s;
	uint16_t a_slots = artNetInterface->numberOfSlots();
	uint16_t s_slots = sACNInterface->numberOfSlots();
	for (int i=1; i <=DMX_UNIVERSE_SIZE; i++) {
		if ( i <= a_slots ) {
			a = artNetInterface->getSlot(i);
		} else {
			a = 0;
		}
		if ( i <= s_slots ) {
			s = sACNInterface->getSlot(i);
		} else {
			s = 0;
		}
		if ( a > s ) {
      	ESP32DMX.setSlot(i , a);
      } else {
      	ESP32DMX.setSlot(i , s);
      }
   }
   ESP32DMX.setMaxSlots(512);
}

/************************************************************************

  Checks to see if packet is a config packet.
  
     In the case it is a query, it replies with the current config from persistent storage.
     
     In the case of upload, it copies the payload to persistent storage
     and also replies with the config settings.
  
*************************************************************************/

void checkConfigReceived(LXDMXWiFi* interface, WiFiUDP* cUDP) {
	if ( strcmp(CONFIG_PACKET_IDENT, (const char *) interface->packetBuffer()) == 0 ) {	//match header to config packet
		Serial.print("config packet received, ");
		uint8_t reply = 0;
		if ( interface->packetBuffer()[8] == '?' ) {	//packet opcode is query
			DMXWiFiConfig.readFromPersistentStore();
			reply = 1;
		} else if (( interface->packetBuffer()[8] == '!' ) && (interface->packetSize() >= 171)) { //packet opcode is set
			Serial.println("upload packet");
			DMXWiFiConfig.copyConfig( interface->packetBuffer(), interface->packetSize());
			DMXWiFiConfig.commitToPersistentStore();
			reply = 1;
		} else if ( interface->packetBuffer()[8] == '^' ) {
			ESP.restart();
		} else {
			Serial.println("unknown config opcode.");
	  	}
		if ( reply) {
			DMXWiFiConfig.hidePassword();													// don't transmit password!
			cUDP->beginPacket(cUDP->remoteIP(), interface->dmxPort());				// unicast reply
			cUDP->write((uint8_t*)DMXWiFiConfig.config(), DMXWiFiConfigSIZE);
			cUDP->endPacket();
      Serial.println(DMXWiFiConfig.SSID());
			Serial.println("reply complete.");
			DMXWiFiConfig.restorePassword();
		}
		interface->packetBuffer()[0] = 0; //insure loop without recv doesn't re-trigger
		interface->packetBuffer()[1] = 0;
		blinkLED();
		delay(100);
		blinkLED();
		delay(100);
		blinkLED();
	}		// packet has config packet header
}

/************************************************************************

  Checks to see if the dmx callback indicates received dmx
     If so, send it using the selected interface.
  
*************************************************************************/

void checkInput(LXDMXWiFi* interface, WiFiUDP* iUDP, uint8_t multicast) {
	if ( got_dmx ) {
		interface->setNumberOfSlots(got_dmx);			// set slots & copy to interface
		for(int i=1; i<=got_dmx; i++) {
		  interface->setSlot(i, ESP32DMX.getSlot(i));
		}
		if ( multicast ) {
			interface->sendDMX(iUDP, DMXWiFiConfig.inputAddress(), WiFi.localIP());
		} else {
			interface->sendDMX(iUDP, DMXWiFiConfig.inputAddress(), INADDR_NONE);
		}
      got_dmx = 0;
      blinkLED();
    }       // got_dmx
}

/************************************************************************

  Main loop
  
  if OUTPUT_FROM_NETWORK_MODE:
    checks for and reads packets from WiFi UDP socket
    connection.  readDMXPacket() returns true when a DMX packet is received.
    
    If dmx is received on either interface, copy from both (HTP) to dmx output.
  
    If the packet is an CONFIG_PACKET_IDENT packet, the config struct is modified and stored in EEPROM
  
  if INPUT_TO_NETWORK_MODE:
    if serial dmx has been received, sends an sACN or Art-Net packet containing the dmx data.
    Note:  does not listen for incoming packets for remote configuration in this mode.

#include <LXWiFiArtNet.h>
#include <LXWiFiSACN.h>
#include "LXDMXWiFiConfig.h"
#include "freertos/task.h"

#define STARTUP_MODE_PIN 18      // pin for force default setup when low (use 10k pullup to insure high)
#define DIRECTION_PIN 21          // pin for output direction enable on MAX481 chip

#define STATUS_LED 19

#define DEBUG_PIN_A 22
#define DEBUG_PIN_B 23
#define DEBUG_PIN_C 14

char ssid[32];
char password[32];

// RDM defines
#define DISC_STATE_SEARCH 0
#define DISC_STATE_TBL_CK 1
/*
   If RDM_DISCOVER_ALWAYS == 0, the times RDM discovery runs is limited to 10 cycles
   of table check and search.  When rdm_discovery_enable reaches zero, continous RDM
   discovery stops.  Other ArtRDM packets continue to be relayed.
   If an Art-Net TODRequest or TODControl packet is received, the rdm_discovery_enable
   counter is reset and discovery runs again until rdm_discovery_enable reaches zero.
*/
#define RDM_DISCOVER_ALWAYS 0

/*
    Edit the LXDMXWiFiConfig.initConfig() function in LXDMXWiFiConfig.cpp to configure the WiFi connection and protocol options
*/

// dmx protocol interfaces for parsing packets (created in setup)
