     Serial.print("created access point at ");
     Serial.print(DMXWiFiConfig.apIPAddress());
     WiFi.softAPConfig(DMXWiFiConfig.apIPAddress(), DMXWiFiConfig.apGateway(), DMXWiFiConfig.apSubnet());
-    
+
     Serial.print(" accessPoint SSID ");
     Serial.print(DMXWiFiConfig.SSID());
-   
+
     Serial.print(", ");
   } else {
     Serial.print("wifi connecting to ");
     Serial.print(DMXWiFiConfig.SSID());
-    Serial.print(" ... ");
+    Serial.print("... ");
     WiFi.mode(WIFI_STA);
-    WiFi.begin(DMXWiFiConfig.SSID(),DMXWiFiConfig.password());
+    strcpy(ssid, DMXWiFiConfig.SSID());
+    strcpy(password, DMXWiFiConfig.password());
+    WiFi.begin((const char*)ssid, (const char*)password);
 
     // static IP otherwise uses DHCP
-    if ( DMXWiFiConfig.staticIPAddress() ) {  
+    if ( DMXWiFiConfig.staticIPAddress() ) {
+      Serial.print("static IP");
       WiFi.config(DMXWiFiConfig.stationIPAddress(), DMXWiFiConfig.stationGateway(), DMXWiFiConfig.stationSubnet());
     } else {
       dhcpStatus = 1;

        if ( result ) {
          //this range responded, so divide into sub ranges push them on stack to be further checked
          pushActiveBranch(lower, upper);
           
        } else if ( ESP32DMX.sendRDMDiscoveryPacket(lower, upper, &found) ) {
            pushActiveBranch(lower, upper); //if discovery fails, try a second time
        }
      }         // end check range
      return 1; // UID ranges may be remaining to test
    }           // end valid pop
  }             // end valid pop  
  return 0;     // none left to pop
}

void sendTODifChanged() {
  if ( tableChangedFlag ) {   //if the table has changed...
    tableChangedFlag--;
    
    artNetInterface->send_art_tod(&aUDP, tableOfDevices.rawBytes(), tableOfDevices.count());

    Serial.println("_______________ Table Of Devices _______________");

  }
  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();


  // increase the priority of this task (main.cpp sets it at 1);
  vTaskPrioritySet(xTaskGetCurrentTaskHandle(), 2);
  
  Serial.print("number of tasks is ");
  Serial.println(uxTaskGetNumberOfTasks());
  /*
  char taskinfo[256];
  TaskStatus_t tslist[10];
  uint32_t trt;
  uxTaskGetSystemState(tslist, 10, &trt);
  //vTaskList(taskinfo);
  //Serial.println(taskinfo);*/

} //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();
  xSemaphoreTake( ESP32DMX.lxDataLock, portMAX_DELAY );
  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);
  xSemaphoreGive( ESP32DMX.lxDataLock );
}

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

  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.
