// Includes //#include //#include #include #include #include #include #include "e131.h" #include #include "FastLED_RGBW.h" #include "config.h" #include #include #include // Begin code bool core1_separate_stack = true; #ifdef DEBUG #define PRINTFUNC print #define PRINTLNFUNC println #else #define PRINTFUNC #define PRINTLNFUNC #endif int calculate[LED_STRIPS * 4]; int universes[LED_STRIPS * 4]; #ifdef RGBW_MODE // EVIL! hack to support RGBW ICs CRGBW leds[MAX_LEDS]; CRGB *ledstrip = (CRGB *) &leds[0]; // yes, we just casted a 4-byte value array to a pseudo 3-byte value array int strips[LED_STRIPS] = {getRGBWsize(128), getRGBWsize(128), getRGBWsize(128), getRGBWsize(128), getRGBWsize(128), getRGBWsize(128), getRGBWsize(128), getRGBWsize(128)}; #else int strips[LED_STRIPS] = {170, 170, 170, 170, 170, 170, 170, 170}; CRGB ledstrip[MAX_LEDS]; #endif int pins[8]; uint8_t * livedata; // Networking WebServer httpServer(80); HTTPUpdateServer httpUpdater; bool status = 0; bool status2 = 0; byte ready = 0; bool newconfig = false; struct tm timeinfo; String clientbuffer = ""; String initinfo = ""; bool debug = 1; bool printer = 1; int channels = 0; // Colors (RGB) int bootsel_count = 0; int nopackets = 0; const uint8_t RED[PIXEL_SIZE]= {0x20, 0x00, 0x00}; const uint8_t ORANGE[PIXEL_SIZE]= {0x20, 0x10, 0x00}; const uint8_t YELLOW[PIXEL_SIZE]= {0x20, 0x20, 0x00}; const uint8_t GREEN[PIXEL_SIZE]= {0x00, 0x20, 0x00}; const uint8_t CYAN[PIXEL_SIZE]= {0x00, 0x20, 0x20}; const uint8_t BLUE[PIXEL_SIZE]= {0x00, 0x00, 0x20}; const uint8_t PURPLE[PIXEL_SIZE]= {0x20, 0x00, 0x20}; const uint8_t BLACK[PIXEL_SIZE]= {0x00, 0x00, 0x00}; const uint8_t WHITE[PIXEL_SIZE]= {0x20, 0x20, 0x20}; #define MAX_PIXELS_PER_UNIVERSE 512 / PIXEL_SIZE /* Number of pixels */ #define CHANNEL_START 1 /* Channel to start listening at */ Wiznet5500lwIP eth(17, SPI, 21); //, 21); // 17 : cs, 21 : INTn E131 e131; float cputemparray[TEMP_SAMPLES]; float airtemparray[TEMP_SAMPLES]; float cputemp; float airtemp; int datapos = 0; template T print(T in) { if(Serial) Serial.print(String(millis()/1000.0) + ": " + String(in)); if(printer) clientbuffer += String(in); return (T)true; } template T println(T in) { if(Serial) Serial.println(String(millis()/1000.0) + ": " + String(in)); if(printer) { clientbuffer += String(in); clientbuffer += "\n"; } return (T)true; } void wipe_eeprom() { for(int i = 0; i < 64+16; i++) { EEPROM.write(i, (byte)0); } EEPROM.commit(); } IPAddress IP_ADDR; unsigned short START_UNIVERSE; char HOSTNAME[64]; String ETH_MODE; String postForms; void handleRoot() { httpServer.send(200, "text/html", postForms); } void handlePlain() { if (httpServer.method() != HTTP_POST) { httpServer.send(405, "text/plain", "Method Not Allowed"); } else { httpServer.send(200, "text/plain", "POST body was:\r\n" + httpServer.arg("plain")); println("POST body was:\r\n" + httpServer.arg("plain")); } } void handleForm() { if (httpServer.method() != HTTP_POST) { httpServer.send(405, "text/plain", "Method Not Allowed"); } else { String message = "POST form was:\r\n"; bool ipset = false; bool reboot = false; for (uint8_t i = 0; i < httpServer.args(); i++) { println(httpServer.argName(i)); if (httpServer.argName(i) == "ipa") { ipset = true; } if (httpServer.argName(i) == "hostname") { println("Updating hostname"); for (int j = 0; j < sizeof(HOSTNAME); j++) { if (j < sizeof(httpServer.arg(i))) HOSTNAME[j] = httpServer.arg(i)[j]; else HOSTNAME[j] = '\0'; } //HOSTNAME = httpServer.arg(i); EEPROM.put(8, HOSTNAME); newconfig = true; //EEPROM.commit(); } if (httpServer.argName(i) == "universe") { println("Updating start universe"); START_UNIVERSE = (unsigned short)(httpServer.arg(i).toInt()); EEPROM.put(4, START_UNIVERSE); newconfig = true; //EEPROM.commit(); } if (httpServer.argName(i) == "reboot") { println("Rebooting..."); reboot = true; } message += " " + httpServer.argName(i) + ": " + httpServer.arg(i) + "\r\n"; } if (ipset) { println("Updating IP address..."); byte a, b, c, d; for (uint8_t i = 0; i < httpServer.args(); i++) { if (httpServer.argName(i) == "ipa") a = byte(httpServer.arg(i).toInt()); if (httpServer.argName(i) == "ipb") b = byte(httpServer.arg(i).toInt()); if (httpServer.argName(i) == "ipc") c = byte(httpServer.arg(i).toInt()); if (httpServer.argName(i) == "ipd") d = byte(httpServer.arg(i).toInt()); } IP_ADDR = IPAddress(a,b,c,d); EEPROM.write(0, a); EEPROM.write(1, b); EEPROM.write(2, c); EEPROM.write(3, d); newconfig = true; } httpServer.sendHeader("Location", "/",true); httpServer.send(302, "text/plain", ""); //httpServer.send(200, "text/plain", message); println(message); if(reboot) { EEPROM.commit(); for (int i = 0; i < MAX_LEDS; i++) { ledstrip[i] = CRGB(0, 0, 0); } FastLED.show(); ready = 3; // trigger core 1 to stop delay(250); rp2040.reboot(); } } } void handleNotFound() { String message = "File Not Found\n\n"; message += "URI: "; message += httpServer.uri(); message += "\nMethod: "; message += (httpServer.method() == HTTP_GET) ? "GET" : "POST"; message += "\nArguments: "; message += httpServer.args(); message += "\n"; for (uint8_t i = 0; i < httpServer.args(); i++) { message += " " + httpServer.argName(i) + ": " + httpServer.arg(i) + "\n"; } httpServer.send(404, "text/plain", message); println(message); } void write_universe(long universe, uint8_t data[], long size) { // universe starts at 0 //print("Universe: "); //Serial.println(universe); //print("Calculate size: "); //Serial.println(sizeof(calculate)); int offset = calculate[universe]; //print("Offset: "); //Serial.println(offset); //print("Universes size: "); //Serial.println(sizeof(universes)); int write_size = universes[universe]; /*print("Length: "); Serial.println(write_size * PIXEL_SIZE + (CHANNEL_START - 1) + 2); print("Data: "); Serial.println(size);*/ if (write_size * PIXEL_SIZE + (CHANNEL_START - 1) > size) { println("Write size too big!!"); println(String(write_size * PIXEL_SIZE + (CHANNEL_START - 1)) + " with data size " + String(size)); return; } /*if(offset + write_size > sizeof(ledstrip)) { println("Write size too big!!"); println(String(offset + write_size) + " with strip size " + sizeof(ledstrip)); return; }*/ //status = 0; for (int i = 0; i < write_size; i++) { int j = i * PIXEL_SIZE + (CHANNEL_START - 1); /*if(debug) { Serial.print(data[j]); Serial.print(" "); Serial.print(data[j+1]); Serial.print(" "); Serial.print(data[j+2]); Serial.print(" "); }*/ #ifdef RGBW_MODE ledstrip[offset + i] = CRGB(data[j], data[j+1], data[j+2]); #else ledstrip[offset + i] = CRGB(data[j], data[j+1], data[j+2]); #endif //ledstrip[strip].setPixelColor(i + offset, data[j], data[j+1], data[j+2]); } //FastLED.show(); //status = 1; //println("Done writing."); } void setup() { vreg_voltage v = VREG_VOLTAGE_1_20; vreg_set_voltage(v); set_sys_clock_khz(252000, false); pinMode(23, OUTPUT); pinMode(23, HIGH); //Serial.begin(115200); //rp2040.wdt_begin(8000); //pinMode(24, INPUT); // VBUS detect - check for USB connection //if (digitalRead(24)) { // delay(3000); // Wait for serial //} pinMode(21, INPUT); // interrupt for W500 Serial.println(""); println("Starting RGB Controller..."); pinMode(20, OUTPUT); println("Resetting W5500 Ethernet Driver..."); digitalWrite(20, LOW); // reset W5500 ethernet delay(1); // for 1 ms digitalWrite(20, HIGH); SPI.setRX(16); SPI.setCS(17); SPI.setSCK(18); SPI.setTX(19); pinMode(ENABLEPIN, OUTPUT); println("Enabling outputs..."); digitalWrite(ENABLEPIN, LOW); // Enable buffer output! //pinMode(0, OUTPUT); //digitalWrite(0, HIGH); //delay(3000); println("Checking for EEPROM configuration..."); EEPROM.begin(256); //wipe_eeprom(); EEPROM.get(4, START_UNIVERSE); if (START_UNIVERSE == 0 || START_UNIVERSE == 65535) { println("No valid config detected. Setting defaults..."); START_UNIVERSE = 1; EEPROM.put(4, START_UNIVERSE); EEPROM.commit(); } if(EEPROM.read(8) == byte(0)) { // check if EEPROM is empty char newhostname[] = "RGBController"; for (int j = 0; j < sizeof(HOSTNAME); j++) { if (j < sizeof(newhostname)) HOSTNAME[j] = newhostname[j]; else HOSTNAME[j] = '\0'; } EEPROM.put(8, HOSTNAME); EEPROM.commit(); } EEPROM.get(8, HOSTNAME); if (HOSTNAME == "") { char newhostname[] = "RGBController"; for (int j = 0; j < sizeof(HOSTNAME); j++) { if (j < sizeof(newhostname)) HOSTNAME[j] = newhostname[j]; else HOSTNAME[j] = '\0'; } EEPROM.put(8, HOSTNAME); EEPROM.commit(); } IP_ADDR = IPAddress(EEPROM.read(0),EEPROM.read(1),EEPROM.read(2),EEPROM.read(3)); //IP_ADDR = IPAddress(192,168,5,5); if (!IP_ADDR.isSet()) ETH_MODE = "dhcp"; else ETH_MODE = "staticip"; rp2040.wdt_reset(); println("Configuration loaded."); if(ETH_MODE == "staticip") { println("Setting static IP..."); eth.config(IP_ADDR, INADDR_NONE); } else { println(F("Requesting Address via DHCP...")); } SPI.setRX(16); SPI.setCS(17); SPI.setSCK(18); SPI.setTX(19); eth.setSPISpeed(ETH_SPI_SPD); lwipPollingPeriod(1); //char * hostname_char; //HOSTNAME.toCharArray(hostname_char, 32); eth.setHostname(HOSTNAME); if (!eth.begin()) { println("No wired Ethernet hardware detected. Check pinouts, wiring."); println("Connection failed. Retrying."); rp2040.reboot(); } int count = 0; while (!eth.connected() && count < 32) { rp2040.wdt_reset(); count++; print("."); delay(250); } if (!eth.connected()) { println("Connection failed. Retrying."); rp2040.reboot(); } print("- IP Address: "); Serial.println(eth.localIP()); e131.begin(E131_UNICAST); #ifdef INT_WIFI WiFi.noLowPowerMode(); #endif // If we get here, then network is good to go println("Starting mDNS client..."); MDNS.begin(HOSTNAME); println("Starting web configurator & firmware update service..."); httpUpdater.setup(&httpServer, update_path, update_username, update_password); httpServer.on("/", handleRoot); httpServer.on("/postplain/", handlePlain); postForms = "\ \ RGB Controller Configuration\ \ \ \

RGB Controller Configuration


\

Set IP address

\ Needs reboot to apply
\ Set to 0.0.0.0 for DHCP\
\ .\ .\ .\ \ \

\

Set Hostname

\ Needs reboot to apply
\ Max 64 characters\
\ \ \

\

DMX512 Start Universe

\ Applies immediately
\ Between (inclusive) 1-65000\
\ \ \

\
\ \

\ \ "; httpServer.on("/postform/", handleForm); httpServer.onNotFound(handleNotFound); httpServer.begin(); MDNS.addService("http", "tcp", 80); print("OTA Updates enabled. Open http://"); Serial.print(HOSTNAME); Serial.print(update_path); Serial.print(" in your browser and login with username "); Serial.print(update_username); Serial.print(" and password "); Serial.println(update_password); if(ENABLE_NTP) { println("Starting NTP client."); NTP.begin(ntpserver); NTP.waitSet([]() { Serial.print("."); }, 15000); time_t now = time(nullptr); Serial.println(""); gmtime_r(&now, &timeinfo); print("Current time: "); Serial.println(asctime(&timeinfo)); } ready += 1; while (ready == 1) { delay(50); } println("Starting temperature monitoring..."); pinMode(AIRTEMP_PIN, INPUT); for(int i = 0; i < TEMP_SAMPLES; i++) { cputemparray[i] = analogReadTemp(); airtemparray[i] = analogRead(AIRTEMP_PIN); } println("Startup Complete. Listening for HTTP and e1.31 (sACN) connections..."); initinfo += clientbuffer; //e131.beginMulticast(ssid, passphrase, UNIVERSE); printer = 0; } void setup1() { while(ready == 0) delay(50); pinMode(LED_BUILTIN, OUTPUT); pinMode(32+1, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); println("Initializing LED outputs and universe mappings..."); #ifdef STRIP1 pins[0] = STRIP1; #endif #ifdef STRIP2 pins[1] = STRIP2; #endif #ifdef STRIP3 pins[2] = STRIP3; #endif #ifdef STRIP4 pins[3] = STRIP4; #endif #ifdef STRIP5 pins[4] = STRIP5; #endif #ifdef STRIP6 pins[5] = STRIP6; #endif #ifdef STRIP7 pins[6] = STRIP7; #endif #ifdef STRIP8 pins[7] = STRIP8; #endif // Populate universes and offsets int offsetcount = 0; int currentsize = 0; for (int i = 0; i < LED_STRIPS; i++) { #ifdef RGBW_MODE int tmp = strips[i] * 3 / 4; #else int tmp = strips[i]; #endif print("Strip "); Serial.print(i); Serial.print(", Pin "); Serial.print(pins[i]); Serial.print(", Light count "); Serial.println(tmp); while(tmp > MAX_PIXELS_PER_UNIVERSE) { universes[currentsize] = MAX_PIXELS_PER_UNIVERSE; calculate[currentsize] = offsetcount; print(" Universe "); Serial.print(currentsize + START_UNIVERSE); Serial.print(", Light count "); Serial.print(MAX_PIXELS_PER_UNIVERSE); Serial.print(", Size "); Serial.print(MAX_PIXELS_PER_UNIVERSE * PIXEL_SIZE); Serial.print(", Offset "); Serial.println(calculate[currentsize]); offsetcount += MAX_PIXELS_PER_UNIVERSE; currentsize += 1; tmp -= MAX_PIXELS_PER_UNIVERSE; } universes[currentsize] = tmp; calculate[currentsize] = offsetcount; print(" Universe "); Serial.print(currentsize + START_UNIVERSE); Serial.print(", Light count "); Serial.print(tmp); Serial.print(", Size "); Serial.print(tmp * PIXEL_SIZE); Serial.print(", Offset "); Serial.println(calculate[currentsize]); offsetcount += tmp; currentsize += 1; } #ifdef STRIP1 FastLED.addLeds(ledstrip, calculate[0], strips[0]); #endif #ifdef STRIP2 FastLED.addLeds(ledstrip, calculate[1], strips[1]); #endif #ifdef STRIP3 FastLED.addLeds(ledstrip, calculate[2], strips[2]); #endif #ifdef STRIP4 FastLED.addLeds(ledstrip, calculate[3], strips[3]); #endif #ifdef STRIP5 FastLED.addLeds(ledstrip, calculate[4], strips[4]); #endif #ifdef STRIP6 FastLED.addLeds(ledstrip, calculate[5], strips[5]); #endif #ifdef STRIP7 FastLED.addLeds(ledstrip, calculate[6], strips[6]); #endif #ifdef STRIP8 FastLED.addLeds(ledstrip, calculate[7], strips[7]); #endif for (int i = 0; i < MAX_LEDS; i++) { ledstrip[i] = CRGB(0, 0, 0); } FastLED.show(); // Test all lights #ifdef LIGHTTEST for (int i = 0; i < MAX_LEDS; i++) { ledstrip[i] = CRGB(0, 0, 50); FastLED.show(); delay(1); ledstrip[i] = CRGB(0, 0, 0); } FastLED.show(); #endif //delay(3000); ready += 1; while (ready == 1) { delay(50); } //rp2040.wdt_begin(8000); } void loop() { /* Parse a packet */ //println("Start loop"); if (millis() % 100 > 50) { // reset LED digitalWrite(LED_BUILTIN, HIGH); } if(channels = e131.parsePacket()) { // Offset by start universe // as all local functions count from 0 //delay(0); livedata = e131.data; status = 1; delayMicroseconds(3000); //print(eth.isLinked()); nopackets = 0; } else { nopackets++; } if(nopackets > 50000) { nopackets = 0; println("No packets processed recently."); delay(5); } //println("mid loop"); httpServer.handleClient(); MDNS.update(); //println("end loop"); if(newconfig == true) { println("Waiting for core 1 to idle..."); ready = 3; while(ready == 3) delay(50); println("Configuration changed - saving to flash..."); EEPROM.commit(); newconfig = false; ready = 2; } } void loop1() { //rp2040.wdt_reset(); if (millis() % 100 < 50) { //status = 0; digitalWrite(LED_BUILTIN, LOW); } if(BOOTSEL) { bootsel_count++; delay(50); } else { bootsel_count = 0; } if(bootsel_count > 60) { // 3 seconds print("Wiping configuration..."); digitalWrite(LED_BUILTIN, LOW); delay(50); for(int i = 0; i < 5; i++) { // blink 5 times to indicate wipe digitalWrite(LED_BUILTIN, HIGH); delay(125); digitalWrite(LED_BUILTIN, LOW); delay(125); } wipe_eeprom(); rp2040.reboot(); } if(ready == 3) { ready = 4; while(ready == 4) delay(50); } status2 = 1; if(status == 1 && e131.universe > START_UNIVERSE - 1 && channels > 0) { write_universe(e131.universe - START_UNIVERSE - 1, livedata, channels); FastLED.show(); //println("Done Writing"); status = 0; } status2 = 0; //status = 0; //delay(50); float cputemp2 = analogReadTemp(); float airtemp2 = analogRead(AIRTEMP_PIN); airtemp2 = airtemp2 / 1024.0 * 3300; // voltage in mV airtemp2 /= 10.0; // 10.0 mv/C airtemp2 -= 50; // offset 500mV = 0C cputemparray[datapos] = cputemp2; airtemparray[datapos] = airtemp2; if(datapos >= TEMP_SAMPLES - 1) { datapos = 0; } else { datapos++; } cputemp2 = 0; airtemp2 = 0; for (int i = 0; i < TEMP_SAMPLES; i++) { if(i != datapos) { cputemp2 += cputemparray[i]; airtemp2 += airtemparray[i]; } } cputemp = cputemp2 / (TEMP_SAMPLES - 1); airtemp = airtemp2 / (TEMP_SAMPLES - 1); // TODO: report temps somehow to dashboard //println("CPUTEMP " + String(cputemp) + " AIRTEMP " + String(airtemp)); }