diff --git a/Arduino/LEDstream/LEDstream.ino b/Arduino/LEDstream/LEDstream.ino deleted file mode 100644 index 629ad9e..0000000 --- a/Arduino/LEDstream/LEDstream.ino +++ /dev/null @@ -1,246 +0,0 @@ -// Arduino "bridge" code between host computer and WS2801-based digital -// RGB LED pixels (e.g. Adafruit product ID #322). Intended for use -// with USB-native boards such as Teensy or Adafruit 32u4 Breakout; -// works on normal serial Arduinos, but throughput is severely limited. -// LED data is streamed, not buffered, making this suitable for larger -// installations (e.g. video wall, etc.) than could otherwise be held -// in the Arduino's limited RAM. - -// Some effort is put into avoiding buffer underruns (where the output -// side becomes starved of data). The WS2801 latch protocol, being -// delay-based, could be inadvertently triggered if the USB bus or CPU -// is swamped with other tasks. This code buffers incoming serial data -// and introduces intentional pauses if there's a threat of the buffer -// draining prematurely. The cost of this complexity is somewhat -// reduced throughput, the gain is that most visual glitches are -// avoided (though ultimately a function of the load on the USB bus and -// host CPU, and out of our control). - -// LED data and clock lines are connected to the Arduino's SPI output. -// On traditional Arduino boards, SPI data out is digital pin 11 and -// clock is digital pin 13. On both Teensy and the 32u4 Breakout, -// data out is pin B2, clock is B1. LEDs should be externally -// powered -- trying to run any more than just a few off the Arduino's -// 5V line is generally a Bad Idea. LED ground should also be -// connected to Arduino ground. - -// -------------------------------------------------------------------- -// This file is part of Adalight. - -// Adalight is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. - -// Adalight is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. - -// You should have received a copy of the GNU Lesser General Public -// License along with Adalight. If not, see -// . -// -------------------------------------------------------------------- - -#include - -// LED pin for Adafruit 32u4 Breakout Board: -//#define LED_DDR DDRE -//#define LED_PORT PORTE -//#define LED_PIN _BV(PORTE6) -// LED pin for Teensy: -//#define LED_DDR DDRD -//#define LED_PORT PORTD -//#define LED_PIN _BV(PORTD6) -// LED pin for Arduino: -#define LED_DDR DDRB -#define LED_PORT PORTB -#define LED_PIN _BV(PORTB5) - -// A 'magic word' (along with LED count & checksum) precedes each block -// of LED data; this assists the microcontroller in syncing up with the -// host-side software and properly issuing the latch (host I/O is -// likely buffered, making usleep() unreliable for latch). You may see -// an initial glitchy frame or two until the two come into alignment. -// The magic word can be whatever sequence you like, but each character -// should be unique, and frequent pixel values like 0 and 255 are -// avoided -- fewer false positives. The host software will need to -// generate a compatible header: immediately following the magic word -// are three bytes: a 16-bit count of the number of LEDs (high byte -// first) followed by a simple checksum value (high byte XOR low byte -// XOR 0x55). LED data follows, 3 bytes per LED, in order R, G, B, -// where 0 = off and 255 = max brightness. - -static const uint8_t magic[] = {'A','d','a'}; -#define MAGICSIZE sizeof(magic) -#define HEADERSIZE (MAGICSIZE + 3) - -#define MODE_HEADER 0 -#define MODE_HOLD 1 -#define MODE_DATA 2 - -// If no serial data is received for a while, the LEDs are shut off -// automatically. This avoids the annoying "stuck pixel" look when -// quitting LED display programs on the host computer. -static const unsigned long serialTimeout = 15000; // 15 seconds - -void setup() -{ - // Dirty trick: the circular buffer for serial data is 256 bytes, - // and the "in" and "out" indices are unsigned 8-bit types -- this - // much simplifies the cases where in/out need to "wrap around" the - // beginning/end of the buffer. Otherwise there'd be a ton of bit- - // masking and/or conditional code every time one of these indices - // needs to change, slowing things down tremendously. - uint8_t - buffer[256], - indexIn = 0, - indexOut = 0, - mode = MODE_HEADER, - hi, lo, chk, i, spiFlag; - int16_t - bytesBuffered = 0, - hold = 0, - c; - int32_t - bytesRemaining; - unsigned long - startTime, - lastByteTime, - lastAckTime, - t; - - LED_DDR |= LED_PIN; // Enable output for LED - LED_PORT &= ~LED_PIN; // LED off - - Serial.begin(115200); // Teensy/32u4 disregards baud rate; is OK! - - SPI.begin(); - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); - SPI.setClockDivider(SPI_CLOCK_DIV16); // 1 MHz max, else flicker - - // Issue test pattern to LEDs on startup. This helps verify that - // wiring between the Arduino and LEDs is correct. Not knowing the - // actual number of LEDs connected, this sets all of them (well, up - // to the first 25,000, so as not to be TOO time consuming) to red, - // green, blue, then off. Once you're confident everything is working - // end-to-end, it's OK to comment this out and reprogram the Arduino. - uint8_t testcolor[] = { 0, 0, 0, 255, 0, 0 }; - for(char n=3; n>=0; n--) { - for(c=0; c<25000; c++) { - for(i=0; i<3; i++) { - for(SPDR = testcolor[n + i]; !(SPSR & _BV(SPIF)); ); - } - } - delay(1); // One millisecond pause = latch - } - - Serial.print("Ada\n"); // Send ACK string to host - - startTime = micros(); - lastByteTime = lastAckTime = millis(); - - // loop() is avoided as even that small bit of function overhead - // has a measurable impact on this code's overall throughput. - - for(;;) { - - // Implementation is a simple finite-state machine. - // Regardless of mode, check for serial input each time: - t = millis(); - if((bytesBuffered < 256) && ((c = Serial.read()) >= 0)) { - buffer[indexIn++] = c; - bytesBuffered++; - lastByteTime = lastAckTime = t; // Reset timeout counters - } else { - // No data received. If this persists, send an ACK packet - // to host once every second to alert it to our presence. - if((t - lastAckTime) > 1000) { - Serial.print("Ada\n"); // Send ACK string to host - lastAckTime = t; // Reset counter - } - // If no data received for an extended time, turn off all LEDs. - if((t - lastByteTime) > serialTimeout) { - for(c=0; c<32767; c++) { - for(SPDR=0; !(SPSR & _BV(SPIF)); ); - } - delay(1); // One millisecond pause = latch - lastByteTime = t; // Reset counter - } - } - - switch(mode) { - - case MODE_HEADER: - - // In header-seeking mode. Is there enough data to check? - if(bytesBuffered >= HEADERSIZE) { - // Indeed. Check for a 'magic word' match. - for(i=0; (i 0) and multiply by 3 for R,G,B. - bytesRemaining = 3L * (256L * (long)hi + (long)lo + 1L); - bytesBuffered -= 3; - spiFlag = 0; // No data out yet - mode = MODE_HOLD; // Proceed to latch wait mode - } else { - // Checksum didn't match; search resumes after magic word. - indexOut -= 3; // Rewind - } - } // else no header match. Resume at first mismatched byte. - bytesBuffered -= i; - } - break; - - case MODE_HOLD: - - // Ostensibly "waiting for the latch from the prior frame - // to complete" mode, but may also revert to this mode when - // underrun prevention necessitates a delay. - - if((micros() - startTime) < hold) break; // Still holding; keep buffering - - // Latch/delay complete. Advance to data-issuing mode... - LED_PORT &= ~LED_PIN; // LED off - mode = MODE_DATA; // ...and fall through (no break): - - case MODE_DATA: - - while(spiFlag && !(SPSR & _BV(SPIF))); // Wait for prior byte - if(bytesRemaining > 0) { - if(bytesBuffered > 0) { - SPDR = buffer[indexOut++]; // Issue next byte - bytesBuffered--; - bytesRemaining--; - spiFlag = 1; - } - // If serial buffer is threatening to underrun, start - // introducing progressively longer pauses to allow more - // data to arrive (up to a point). - if((bytesBuffered < 32) && (bytesRemaining > bytesBuffered)) { - startTime = micros(); - hold = 100 + (32 - bytesBuffered) * 10; - mode = MODE_HOLD; - } - } else { - // End of data -- issue latch: - startTime = micros(); - hold = 1000; // Latch duration = 1000 uS - LED_PORT |= LED_PIN; // LED on - mode = MODE_HEADER; // Begin next header search - } - } // end switch - } // end for(;;) -} - -void loop() -{ - // Not used. See note in setup() function. -} diff --git a/Arduino/LEDstream_CircuitPlayground/LEDstream_CircuitPlayground.ino b/Arduino/LEDstream_CircuitPlayground/LEDstream_CircuitPlayground.ino deleted file mode 100644 index 6aa3a8c..0000000 --- a/Arduino/LEDstream_CircuitPlayground/LEDstream_CircuitPlayground.ino +++ /dev/null @@ -1,134 +0,0 @@ -// This is a pared-down version of the LEDstream sketch specifically -// for Circuit Playground. It is NOT a generic solution to NeoPixel -// support with Adalight! The NeoPixel library disables interrupts -// while issuing data...but Serial transfers depend on interrupts. -// This code works (or appears to work, it hasn't been extensively -// battle-tested) only because of the finite number of pixels (10) -// on the Circuit Playground board. With 10 NeoPixels, interrupts are -// off for about 300 microseconds...but if the incoming data rate is -// sufficiently limited (<= 60 FPS or so with the given number of -// pixels), things seem OK, no data is missed. Balancing act! - -// -------------------------------------------------------------------- -// This file is part of Adalight. - -// Adalight is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. - -// Adalight is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. - -// You should have received a copy of the GNU Lesser General Public -// License along with Adalight. If not, see -// . -// -------------------------------------------------------------------- - -#include "Adafruit_CircuitPlayground.h" - -static const uint8_t magic[] = { 'A','d','a' }; -#define MAGICSIZE sizeof(magic) -#define HEADERSIZE (MAGICSIZE + 3) -static uint8_t - buffer[HEADERSIZE], // Serial input buffer - bytesBuffered = 0; // Amount of data in buffer - -static const unsigned long serialTimeout = 15000; // 15 seconds -static unsigned long lastByteTime; - -void setup() { - CircuitPlayground.begin(); - CircuitPlayground.setBrightness(255); // LEDs full blast! - CircuitPlayground.strip.clear(); - CircuitPlayground.strip.show(); - - Serial.begin(38400); - - lastByteTime = millis(); // Initialize timers -} - -// Function is called when no pending serial data is available. -static boolean timeout( - unsigned long t, // Current time, milliseconds - int nLEDs) { // Number of LEDs - - // If no data received for an extended time, turn off all LEDs. - if((t - lastByteTime) > serialTimeout) { - CircuitPlayground.strip.clear(); - CircuitPlayground.strip.show(); - lastByteTime = t; // Reset counter - bytesBuffered = 0; // Clear serial buffer - return true; - } - - return false; // No timeout -} - -void loop() { - uint8_t i, hi, lo, byteNum; - int c; - long nLEDs, pixelNum; - unsigned long t; - - // HEADER-SEEKING BLOCK: locate 'magic word' at start of frame. - - // If any data in serial buffer, shift it down to starting position. - for(i=0; i= 0) { // Data received? - buffer[bytesBuffered++] = c; // Store in buffer - lastByteTime = t; // Reset timeout counter - } else { // No data, check for timeout... - if(timeout(t, 10000) == true) return; // Start over - } - } - - // Have a header's worth of data. Check for 'magic word' match. - for(i=0; i 0) - nLEDs = 256L * (long)hi + (long)lo + 1L; - bytesBuffered = 0; // Clear serial buffer - byteNum = 0; - - // DATA-FORWARDING BLOCK: move bytes from serial input to NeoPixels. - - for(pixelNum = 0; pixelNum < nLEDs; ) { // While more LED data is expected... - t = millis(); - if((c = Serial.read()) >= 0) { // Successful read? - lastByteTime = t; // Reset timeout counters - buffer[byteNum++] = c; // Store in data buffer - if(byteNum == 3) { // Have a full LED's worth? - CircuitPlayground.strip.setPixelColor(pixelNum++, - buffer[0], buffer[1], buffer[2]); - byteNum = 0; - } - } else { // No data, check for timeout... - if(timeout(t, nLEDs) == true) return; // Start over - } - } - - CircuitPlayground.strip.show(); -} - diff --git a/Arduino/LEDstream_LPD8806/LEDstream_LPD8806.ino b/Arduino/LEDstream_LPD8806/LEDstream_LPD8806.ino deleted file mode 100644 index 1c2950c..0000000 --- a/Arduino/LEDstream_LPD8806/LEDstream_LPD8806.ino +++ /dev/null @@ -1,250 +0,0 @@ -// Arduino bridge code between host computer and LPD8806-based digital -// addressable RGB LEDs (e.g. Adafruit product ID #306). LED data is -// streamed, not buffered, making this suitable for larger installations -// (e.g. video wall, etc.) than could otherwise be contained within the -// Arduino's limited RAM. Intended for use with USB-native boards such -// as Teensy or Adafruit 32u4 Breakout; also works on normal serial -// Arduinos (Uno, etc.), but speed will be limited by the serial port. - -// LED data and clock lines are connected to the Arduino's SPI output. -// On traditional Arduino boards (e.g. Uno), SPI data out is digital pin -// 11 and clock is digital pin 13. On both Teensy and the 32u4 Breakout, -// data out is pin B2, clock is B1. On Arduino Mega, 51=data, 52=clock. -// LEDs should be externally powered -- trying to run any more than just -// a few off the Arduino's 5V line is generally a Bad Idea. LED ground -// should also be connected to Arduino ground. - -// Elsewhere, the WS2801 version of this code was specifically designed -// to avoid buffer underrun conditions...the WS2801 pixels automatically -// latch when the data stream stops for 500 microseconds or more, whether -// intentional or not. The LPD8806 pixels are fundamentally different -- -// the latch condition is indicated within the data stream, not by pausing -// the clock -- and buffer underruns are therefore a non-issue. In theory -// it would seem this could allow the code to be much simpler and faster -// (there's no need to sync up with a start-of-frame header), but in -// practice the difference was not as pronounced as expected -- such code -// soon ran up against a USB throughput limit anyway. So, rather than -// break compatibility in the quest for speed that will never materialize, -// this code instead follows the same header format as the WS2801 version. -// This allows the same host-side code (e.g. Adalight, Adavision, etc.) -// to run with either type of LED pixels. Huzzah! - -// -------------------------------------------------------------------- -// This file is part of Adalight. - -// Adalight is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. - -// Adalight is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. - -// You should have received a copy of the GNU Lesser General Public -// License along with Adalight. If not, see -// . -// -------------------------------------------------------------------- - -#include - -// A 'magic word' precedes each block of LED data; this assists the -// microcontroller in syncing up with the host-side software and latching -// frames at the correct time. You may see an initial glitchy frame or -// two until the two come into alignment. Immediately following the -// magic word are three bytes: a 16-bit count of the number of LEDs (high -// byte first) followed by a simple checksum value (high byte XOR low byte -// XOR 0x55). LED data follows, 3 bytes per LED, in order R, G, B, where -// 0 = off and 255 = max brightness. LPD8806 pixels only have 7-bit -// brightness control, so each value is divided by two; the 8-bit format -// is used to maintain compatibility with the protocol set forth by the -// WS2801 streaming code (those LEDs use 8-bit values). -static const uint8_t magic[] = { 'A','d','a' }; -#define MAGICSIZE sizeof(magic) -#define HEADERSIZE (MAGICSIZE + 3) -static uint8_t - buffer[HEADERSIZE], // Serial input buffer - bytesBuffered = 0; // Amount of data in buffer - -// If no serial data is received for a while, the LEDs are shut off -// automatically. This avoids the annoying "stuck pixel" look when -// quitting LED display programs on the host computer. -static const unsigned long serialTimeout = 15000; // 15 seconds -static unsigned long lastByteTime, lastAckTime; - -void setup() { - byte c; - int i, p; - - Serial.begin(115200); // 32u4 will ignore BPS and run full speed - - // SPI is run at 2 MHz. LPD8806 can run much faster, - // but unshielded wiring is susceptible to interference. - // Feel free to experiment with other divider ratios. - SPI.begin(); - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); - SPI.setClockDivider(SPI_CLOCK_DIV8); // 2 MHz - - // Issue dummy byte to "prime" the SPI bus. This later simplifies - // the task of doing useful work during SPI transfers. Rather than - // the usual issue-and-wait-loop, code can instead wait-and-issue -- - // with other operations occurring between transfers, the wait is - // then shortened or eliminated. The SPSR register is read-only, - // so this flag can't be forced -- SOMETHING must be issued. - SPDR = 0; - - // Issue initial latch to LEDs. This flushes any undefined data that - // may exist on powerup, and prepares the LEDs to receive the first - // frame of data. Actual number of LEDs isn't known yet (this arrives - // later in frame header packets), so just latch a large number: - latch(10000); - - // Issue test pattern to LEDs on startup. This helps verify that - // wiring between the Arduino and LEDs is correct. Again not knowing - // the actual number of LEDs, this writes data for an arbitrarily - // large number (10K). If wiring is correct, LEDs will all light - // red, green, blue on startup, then off. Once you're confident - // everything is working end-to-end, it's OK to comment this out and - // re-upload the sketch to the Arduino. - const uint8_t testColor[] = { 0x80, 0x80, 0xff, 0x80, 0x80, 0x80 }, - testOffset[] = { 1, 2, 0, 3 }; - for(c=0; c<4; c++) { // for each test sequence color... - for(p=0; p<10000; p++) { // for each pixel... - for(i=0; i<3; i++) { // for each R,G,B... - while(!(SPSR & _BV(SPIF))); // Wait for prior byte out - SPDR = testColor[testOffset[c] + i]; // Issue next byte - } - } - latch(10000); - if(c < 3) delay(250); - } - - Serial.print("Ada\n"); // Send ACK string to host - lastByteTime = lastAckTime = millis(); // Initialize timers -} - -// Program flow is simpler than the WS2801 code. No need for a state -// machine...instead, software just alternates between two conditions: -// a header-seeking mode (looking for the 'magic word' at the start -// of each frame of data), and a data-forwarding mode (moving bytes -// from serial input to SPI output). A proper data stream will -// consist only of alternating valid headers and valid data, so the -// loop() function is simply divided into these two parts, and repeats -// forever. - -// LPD8806 pixels expect colors in G,R,B order vs. WS2801's R,G,B. -// This is used to shuffle things around later. -static const uint8_t byteOrder[] = { 2, 0, 1 }; - -void loop() { - uint8_t i, hi, lo, byteNum; - int c; - long nLEDs, remaining; - unsigned long t; - - // HEADER-SEEKING BLOCK: locate 'magic word' at start of frame. - - // If any data in serial buffer, shift it down to starting position. - for(i=0; i= 0) { // Data received? - buffer[bytesBuffered++] = c; // Store in buffer - lastByteTime = lastAckTime = t; // Reset timeout counters - } else { // No data, check for timeout... - if(timeout(t, 10000) == true) return; // Start over - } - } - - // Have a header's worth of data. Check for 'magic word' match. - for(i=0; i 0) - nLEDs = remaining = 256L * (long)hi + (long)lo + 1L; - bytesBuffered = 0; // Clear serial buffer - byteNum = 0; - - // DATA-FORWARDING BLOCK: move bytes from serial input to SPI output. - - // Unfortunately can't just forward bytes directly. The data order is - // different on LPD8806 (G,R,B), so bytes are buffered in groups of 3 - // and issued in the revised order. - - while(remaining > 0) { // While more LED data is expected... - t = millis(); - if((c = Serial.read()) >= 0) { // Successful read? - lastByteTime = lastAckTime = t; // Reset timeout counters - buffer[byteNum++] = c; // Store in data buffer - if(byteNum == 3) { // Have a full LED's worth? - while(byteNum > 0) { // Issue data in LPD8806 order... - i = 0x80 | (buffer[byteOrder[--byteNum]] >> 1); - while(!(SPSR & _BV(SPIF))); // Wait for prior byte out - SPDR = i; // Issue new byte - } - remaining--; - } - } else { // No data, check for timeout... - if(timeout(t, nLEDs) == true) return; // Start over - } - } - - // Normal end of data. Issue latch, return to header-seeking mode. - latch(nLEDs); -} - -static void latch(int n) { // Pass # of LEDs - n = ((n + 63) / 64) * 3; // Convert to latch length (bytes) - while(n--) { // For each latch byte... - while(!(SPSR & _BV(SPIF))); // Wait for prior byte out - SPDR = 0; // Issue next byte - } -} - -// Function is called when no pending serial data is available. -static boolean timeout( - unsigned long t, // Current time, milliseconds - int nLEDs) { // Number of LEDs - - // If condition persists, send an ACK packet to host once every - // second to alert it to our presence. - if((t - lastAckTime) > 1000) { - Serial.print("Ada\n"); // Send ACK string to host - lastAckTime = t; // Reset counter - } - - // If no data received for an extended time, turn off all LEDs. - if((t - lastByteTime) > serialTimeout) { - long bytes = nLEDs * 3L; - latch(nLEDs); // Latch any partial/incomplete data in strand - while(bytes--) { // Issue all new data to turn off strand - while(!(SPSR & _BV(SPIF))); // Wait for prior byte out - SPDR = 0x80; // Issue next byte (0x80 = LED off) - } - latch(nLEDs); // Latch 'all off' data - lastByteTime = t; // Reset counter - bytesBuffered = 0; // Clear serial buffer - return true; - } - - return false; // No timeout -} - diff --git a/C/Makefile b/C/Makefile deleted file mode 100644 index 7d40df7..0000000 --- a/C/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -EXECS = colorswirl - -all: $(EXECS) - -colorswirl: colorswirl.c - cc -O2 colorswirl.c -lm -o colorswirl - -clean: - rm -f $(EXECS) *.o diff --git a/C/colorswirl.c b/C/colorswirl.c deleted file mode 100644 index 8bdb668..0000000 --- a/C/colorswirl.c +++ /dev/null @@ -1,181 +0,0 @@ -/* -"Colorswirl" LED demo. This is the host PC-side code written in C; -intended for use with a USB-connected Arduino microcontroller running the -accompanying LED streaming code. Requires one strand of Digital RGB LED -Pixels (Adafruit product ID #322, specifically the newer WS2801-based type, -strand of 25) and a 5 Volt power supply (such as Adafruit #276). You may -need to adapt the code and the hardware arrangement for your specific -configuration. - -This is a command-line program. It expects a single parameter, which is -the serial port device name, e.g.: - - ./colorswirl /dev/tty.usbserial-A60049KO - -*/ - -// -------------------------------------------------------------------- -// This file is part of Adalight. - -// Adalight is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. - -// Adalight is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. - -// You should have received a copy of the GNU Lesser General Public -// License along with Adalight. If not, see -// . -// -------------------------------------------------------------------- - -#include -#include -#include -#include -#include -#include - -#define N_LEDS 25 // Max of 65536 - -int main(int argc,char *argv[]) -{ - int fd, i, bytesToGo, bytesSent, totalBytesSent = 0, - frame = 0, hue1, hue2, brightness; - unsigned char buffer[6 + (N_LEDS * 3)], // Header + 3 bytes per LED - lo, r, g, b; - double sine1, sine2; - time_t t, start, prev; - struct termios tty; - - if(argc < 2) { - (void)printf("Usage: %s device\n", argv[0]); - return 1; - } - - if((fd = open(argv[1],O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) { - (void)printf("Can't open device '%s'.\n", argv[1]); - return 1; - } - - // Serial port config swiped from RXTX library (rxtx.qbang.org): - tcgetattr(fd, &tty); - tty.c_iflag = INPCK; - tty.c_lflag = 0; - tty.c_oflag = 0; - tty.c_cflag = CREAD | CS8 | CLOCAL; - tty.c_cc[ VMIN ] = 0; - tty.c_cc[ VTIME ] = 0; - cfsetispeed(&tty, B115200); - cfsetospeed(&tty, B115200); - tcsetattr(fd, TCSANOW, &tty); - - bzero(buffer, sizeof(buffer)); // Clear LED buffer - - // Header only needs to be initialized once, not - // inside rendering loop -- number of LEDs is constant: - buffer[0] = 'A'; // Magic word - buffer[1] = 'd'; - buffer[2] = 'a'; - buffer[3] = (N_LEDS - 1) >> 8; // LED count high byte - buffer[4] = (N_LEDS - 1) & 0xff; // LED count low byte - buffer[5] = buffer[3] ^ buffer[4] ^ 0x55; // Checksum - - sine1 = 0.0; - hue1 = 0; - prev = start = time(NULL); // For bandwidth statistics - - for(;;) { - sine2 = sine1; - hue2 = hue1; - - // Start at position 6, after the LED header/magic word - for(i = 6; i < sizeof(buffer); ) { - // Fixed-point hue-to-RGB conversion. 'hue2' is an - // integer in the range of 0 to 1535, where 0 = red, - // 256 = yellow, 512 = green, etc. The high byte - // (0-5) corresponds to the sextant within the color - // wheel, while the low byte (0-255) is the - // fractional part between primary/secondary colors. - lo = hue2 & 255; - switch((hue2 >> 8) % 6) { - case 0: - r = 255; - g = lo; - b = 0; - break; - case 1: - r = 255 - lo; - g = 255; - b = 0; - break; - case 2: - r = 0; - g = 255; - b = lo; - break; - case 3: - r = 0; - g = 255 - lo; - b = 255; - break; - case 4: - r = lo; - g = 0; - b = 255; - break; - case 5: - r = 255; - g = 0; - b = 255 - lo; - break; - } - - // Resulting hue is multiplied by brightness in the - // range of 0 to 255 (0 = off, 255 = brightest). - // Gamma corrrection (the 'pow' function here) adjusts - // the brightness to be more perceptually linear. - brightness = (int)(pow(0.5+sin(sine2)*0.5,3.0)*255.0); - buffer[i++] = (r * brightness) / 255; - buffer[i++] = (g * brightness) / 255; - buffer[i++] = (b * brightness) / 255; - - // Each pixel is offset in both hue and brightness - hue2 += 40; - sine2 += 0.3; - } - - // Slowly rotate hue and brightness in opposite directions - hue1 = (hue1 + 5) % 1536; - sine1 -= .03; - - // Issue color data to LEDs. Each OS is fussy in different - // ways about serial output. This arrangement of drain-and- - // write-loop seems to be the most relable across platforms: - tcdrain(fd); - for(bytesSent=0, bytesToGo=sizeof(buffer); bytesToGo > 0;) { - if((i=write(fd,&buffer[bytesSent],bytesToGo)) > 0) { - bytesToGo -= i; - bytesSent += i; - } - } - // Keep track of byte and frame counts for statistics - totalBytesSent += sizeof(buffer); - frame++; - - // Update statistics once per second - if((t = time(NULL)) != prev) { - (void)printf( - "Average frames/sec: %d, bytes/sec: %d\n", - (int)((float)frame / (float)(t - start)), - (int)((float)totalBytesSent / (float)(t - start))); - prev = t; - } - } - - close(fd); - return 0; -} diff --git a/Processing/Adalight/Adalight.pde b/Processing/Adalight/Adalight.pde deleted file mode 100644 index a8e0d89..0000000 --- a/Processing/Adalight/Adalight.pde +++ /dev/null @@ -1,430 +0,0 @@ -// "Adalight" is a do-it-yourself facsimile of the Philips Ambilight concept -// for desktop computers and home theater PCs. This is the host PC-side code -// written in Processing, intended for use with a USB-connected Arduino -// microcontroller running the accompanying LED streaming code. Requires one -// or more strands of Digital RGB LED Pixels (Adafruit product ID #322, -// specifically the newer WS2801-based type, strand of 25) and a 5 Volt power -// supply (such as Adafruit #276). You may need to adapt the code and the -// hardware arrangement for your specific display configuration. -// Screen capture adapted from code by Cedrik Kiefer (processing.org forum) - -// -------------------------------------------------------------------- -// This file is part of Adalight. - -// Adalight is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. - -// Adalight is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. - -// You should have received a copy of the GNU Lesser General Public -// License along with Adalight. If not, see -// . -// -------------------------------------------------------------------- - -import java.awt.*; -import java.awt.image.*; -import processing.serial.*; - -// CONFIGURABLE PROGRAM CONSTANTS -------------------------------------------- - -// Minimum LED brightness; some users prefer a small amount of backlighting -// at all times, regardless of screen content. Higher values are brighter, -// or set to 0 to disable this feature. - -static final short minBrightness = 120; - -// LED transition speed; it's sometimes distracting if LEDs instantaneously -// track screen contents (such as during bright flashing sequences), so this -// feature enables a gradual fade to each new LED state. Higher numbers yield -// slower transitions (max of 255), or set to 0 to disable this feature -// (immediate transition of all LEDs). - -static final short fade = 75; - -// Pixel size for the live preview image. - -static final int pixelSize = 20; - -// Depending on many factors, it may be faster either to capture full -// screens and process only the pixels needed, or to capture multiple -// smaller sub-blocks bounding each region to be processed. Try both, -// look at the reported frame rates in the Processing output console, -// and run with whichever works best for you. - -static final boolean useFullScreenCaps = true; - -// Serial device timeout (in milliseconds), for locating Arduino device -// running the corresponding LEDstream code. See notes later in the code... -// in some situations you may want to entirely comment out that block. - -static final int timeout = 5000; // 5 seconds - -// PER-DISPLAY INFORMATION --------------------------------------------------- - -// This array contains details for each display that the software will -// process. If you have screen(s) attached that are not among those being -// "Adalighted," they should not be in this list. Each triplet in this -// array represents one display. The first number is the system screen -// number...typically the "primary" display on most systems is identified -// as screen #1, but since arrays are indexed from zero, use 0 to indicate -// the first screen, 1 to indicate the second screen, and so forth. This -// is the ONLY place system screen numbers are used...ANY subsequent -// references to displays are an index into this list, NOT necessarily the -// same as the system screen number. For example, if you have a three- -// screen setup and are illuminating only the third display, use '2' for -// the screen number here...and then, in subsequent section, '0' will be -// used to refer to the first/only display in this list. -// The second and third numbers of each triplet represent the width and -// height of a grid of LED pixels attached to the perimeter of this display. -// For example, '9,6' = 9 LEDs across, 6 LEDs down. - -static final int displays[][] = new int[][] { - {0,9,6} // Screen 0, 9 LEDs across, 6 LEDs down -//,{1,9,6} // Screen 1, also 9 LEDs across and 6 LEDs down -}; - -// PER-LED INFORMATION ------------------------------------------------------- - -// This array contains the 2D coordinates corresponding to each pixel in the -// LED strand, in the order that they're connected (i.e. the first element -// here belongs to the first LED in the strand, second element is the second -// LED, and so forth). Each triplet in this array consists of a display -// number (an index into the display array above, NOT necessarily the same as -// the system screen number) and an X and Y coordinate specified in the grid -// units given for that display. {0,0,0} is the top-left corner of the first -// display in the array. -// For our example purposes, the coordinate list below forms a ring around -// the perimeter of a single screen, with a one pixel gap at the bottom to -// accommodate a monitor stand. Modify this to match your own setup: - -static final int leds[][] = new int[][] { - {0,3,5}, {0,2,5}, {0,1,5}, {0,0,5}, // Bottom edge, left half - {0,0,4}, {0,0,3}, {0,0,2}, {0,0,1}, // Left edge - {0,0,0}, {0,1,0}, {0,2,0}, {0,3,0}, {0,4,0}, // Top edge - {0,5,0}, {0,6,0}, {0,7,0}, {0,8,0}, // More top edge - {0,8,1}, {0,8,2}, {0,8,3}, {0,8,4}, // Right edge - {0,8,5}, {0,7,5}, {0,6,5}, {0,5,5} // Bottom edge, right half - -/* Hypothetical second display has the same arrangement as the first. - But you might not want both displays completely ringed with LEDs; - the screens might be positioned where they share an edge in common. - ,{1,3,5}, {1,2,5}, {1,1,5}, {1,0,5}, // Bottom edge, left half - {1,0,4}, {1,0,3}, {1,0,2}, {1,0,1}, // Left edge - {1,0,0}, {1,1,0}, {1,2,0}, {1,3,0}, {1,4,0}, // Top edge - {1,5,0}, {1,6,0}, {1,7,0}, {1,8,0}, // More top edge - {1,8,1}, {1,8,2}, {1,8,3}, {1,8,4}, // Right edge - {1,8,5}, {1,7,5}, {1,6,5}, {1,5,5} // Bottom edge, right half -*/ -}; - -// GLOBAL VARIABLES ---- You probably won't need to modify any of this ------- - -byte[] serialData = new byte[6 + leds.length * 3]; -short[][] ledColor = new short[leds.length][3], - prevColor = new short[leds.length][3]; -byte[][] gamma = new byte[256][3]; -int nDisplays = displays.length; -Robot[] bot = new Robot[displays.length]; -Rectangle[] dispBounds = new Rectangle[displays.length], - ledBounds; // Alloc'd only if per-LED captures -int[][] pixelOffset = new int[leds.length][256], - screenData; // Alloc'd only if full-screen captures -PImage[] preview = new PImage[displays.length]; -Serial port; -DisposeHandler dh; // For disabling LEDs on exit - -// INITIALIZATION ------------------------------------------------------------ - -void setup() { - GraphicsEnvironment ge; - GraphicsConfiguration[] gc; - GraphicsDevice[] gd; - int d, i, totalWidth, maxHeight, row, col, rowOffset; - int[] x = new int[16], y = new int[16]; - float f, range, step, start; - - dh = new DisposeHandler(this); // Init DisposeHandler ASAP - - // Open serial port. As written here, this assumes the Arduino is the - // first/only serial device on the system. If that's not the case, - // change "Serial.list()[0]" to the name of the port to be used: - port = new Serial(this, Serial.list()[0], 115200); - // Alternately, in certain situations the following line can be used - // to detect the Arduino automatically. But this works ONLY with SOME - // Arduino boards and versions of Processing! This is so convoluted - // to explain, it's easier just to test it yourself and see whether - // it works...if not, leave it commented out and use the prior port- - // opening technique. - // port = openPort(); - // And finally, to test the software alone without an Arduino connected, - // don't open a port...just comment out the serial lines above. - - // Initialize screen capture code for each display's dimensions. - dispBounds = new Rectangle[displays.length]; - if(useFullScreenCaps == true) { - screenData = new int[displays.length][]; - // ledBounds[] not used - } else { - ledBounds = new Rectangle[leds.length]; - // screenData[][] not used - } - ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - gd = ge.getScreenDevices(); - if(nDisplays > gd.length) nDisplays = gd.length; - totalWidth = maxHeight = 0; - for(d=0; d 0) totalWidth++; - if(displays[d][2] > maxHeight) maxHeight = displays[d][2]; - } - - // Precompute locations of every pixel to read when downsampling. - // Saves a bunch of math on each frame, at the expense of a chunk - // of RAM. Number of samples is now fixed at 256; this allows for - // some crazy optimizations in the downsampling code. - for(i=0; i> 8); // LED count high byte - serialData[4] = (byte)((leds.length - 1) & 0xff); // LED count low byte - serialData[5] = (byte)(serialData[3] ^ serialData[4] ^ 0x55); // Checksum - - // Pre-compute gamma correction table for LED brightness levels: - for(i=0; i<256; i++) { - f = pow((float)i / 255.0, 2.8); - gamma[i][0] = (byte)(f * 255.0); - gamma[i][1] = (byte)(f * 240.0); - gamma[i][2] = (byte)(f * 220.0); - } -} - -// Open and return serial connection to Arduino running LEDstream code. This -// attempts to open and read from each serial device on the system, until the -// matching "Ada\n" acknowledgement string is found. Due to the serial -// timeout, if you have multiple serial devices/ports and the Arduino is late -// in the list, this can take seemingly forever...so if you KNOW the Arduino -// will always be on a specific port (e.g. "COM6"), you might want to comment -// out most of this to bypass the checks and instead just open that port -// directly! (Modify last line in this method with the serial port name.) - -Serial openPort() { - String[] ports; - String ack; - int i, start; - Serial s; - - ports = Serial.list(); // List of all serial ports/devices on system. - - for(i=0; i= 4) && - ((ack = s.readString()) != null) && - ack.contains("Ada\n")) { - return s; // Got it! - } - } - // Connection timed out. Close port and move on to the next. - s.stop(); - } - - // Didn't locate a device returning the acknowledgment string. - // Maybe it's out there but running the old LEDstream code, which - // didn't have the ACK. Can't say for sure, so we'll take our - // changes with the first/only serial device out there... - return new Serial(this, ports[0], 115200); -} - - -// PER_FRAME PROCESSING ------------------------------------------------------ - -void draw () { - BufferedImage img; - int d, i, j, o, c, weight, rb, g, sum, deficit, s2; - int[] pxls, offs; - - if(useFullScreenCaps == true ) { - // Capture each screen in the displays array. - for(d=0; d> 24) & 0xff) * weight + - prevColor[i][0] * fade) >> 8); - ledColor[i][1] = (short)(((( g >> 16) & 0xff) * weight + - prevColor[i][1] * fade) >> 8); - ledColor[i][2] = (short)((((rb >> 8) & 0xff) * weight + - prevColor[i][2] * fade) >> 8); - - // Boost pixels that fall below the minimum brightness - sum = ledColor[i][0] + ledColor[i][1] + ledColor[i][2]; - if(sum < minBrightness) { - if(sum == 0) { // To avoid divide-by-zero - deficit = minBrightness / 3; // Spread equally to R,G,B - ledColor[i][0] += deficit; - ledColor[i][1] += deficit; - ledColor[i][2] += deficit; - } else { - deficit = minBrightness - sum; - s2 = sum * 2; - // Spread the "brightness deficit" back into R,G,B in proportion to - // their individual contribition to that deficit. Rather than simply - // boosting all pixels at the low end, this allows deep (but saturated) - // colors to stay saturated...they don't "pink out." - ledColor[i][0] += deficit * (sum - ledColor[i][0]) / s2; - ledColor[i][1] += deficit * (sum - ledColor[i][1]) / s2; - ledColor[i][2] += deficit * (sum - ledColor[i][2]) / s2; - } - } - - // Apply gamma curve and place in serial output buffer - serialData[j++] = gamma[ledColor[i][0]][0]; - serialData[j++] = gamma[ledColor[i][1]][1]; - serialData[j++] = gamma[ledColor[i][2]][2]; - // Update pixels in preview image - preview[d].pixels[leds[i][2] * displays[d][1] + leds[i][1]] = - (ledColor[i][0] << 16) | (ledColor[i][1] << 8) | ledColor[i][2]; - } - - if(port != null) port.write(serialData); // Issue data to Arduino - - // Show live preview image(s) - scale(pixelSize); - for(i=d=0; d. -// -------------------------------------------------------------------- - -import java.awt.*; -import java.awt.image.*; -import processing.serial.*; - -// CONFIGURABLE PROGRAM CONSTANTS -------------------------------------------- - -// This selects from the list of serial devices connected to the system. -// Use print(Serial.list()); to get a list of ports. Then, counting from 0, -// set this value to the index corresponding to the Circuit Playground port: - -static final byte serialPortIndex = 2; - -// For multi-screen systems, set this to the index (counting from 0) of the -// display which will have ambient lighting: - -static final byte screenNumber = 0; - -// Minimum LED brightness; some users prefer a small amount of backlighting -// at all times, regardless of screen content. Higher values are brighter, -// or set to 0 to disable this feature. - -static final short minBrightness = 100; - -// LED transition speed; it's sometimes distracting if LEDs instantaneously -// track screen contents (such as during bright flashing sequences), so this -// feature enables a gradual fade to each new LED state. Higher numbers yield -// slower transitions (max of 255), or set to 0 to disable this feature -// (immediate transition of all LEDs). - -static final short fade = 60; - -// Depending on many factors, it may be faster either to capture full -// screens and process only the pixels needed, or to capture multiple -// smaller sub-blocks bounding each region to be processed. Try both, -// look at the reported frame rates in the Processing output console, -// and run with whichever works best for you. - -static final boolean useFullScreenCaps = true; - -// PER-LED INFORMATION ------------------------------------------------------- - -// The Circuit Playground version of Adalight operates on a fixed 5x5 grid -// encompassing the full display. 10 elements from this grid correspond to -// the 10 NeoPixels on the Circuit Playground board. The following array -// contains the 2D coordinates of each NeoPixel within that 5x5 grid (0,0 is -// top left); board assumed facing away from display, with USB at bottom: -// .4.5. -// 3...6 -// 2...7 -// 1...8 -// .0.9. - -static final int leds[][] = new int[][] { - {1,4}, {0,3}, {0,2}, {0,1}, {1,0}, - {3,0}, {4,1}, {4,2}, {4,3}, {3,4} -}; - -// GLOBAL VARIABLES ---- You probably won't need to modify any of this ------- - -byte serialData[] = new byte[6 + leds.length * 3], - gamma[][] = new byte[256][3]; -short[][] ledColor = new short[leds.length][3], - prevColor = new short[leds.length][3]; -Robot bot; -Rectangle dispBounds, ledBounds[]; -int pixelOffset[][] = new int[leds.length][256], - screenData[]; -PImage preview; -Serial port; - -// INITIALIZATION ------------------------------------------------------------ - -void setup() { - GraphicsEnvironment ge; - GraphicsConfiguration[] gc; - GraphicsDevice[] gd; - int i, row, col; - int[] x = new int[16], y = new int[16]; - float f, range, step, start; - - this.registerMethod("dispose", this); - print(Serial.list()); // Show list of serial devices/ports - // Open serial port. Change serialPortIndex in the globals to - // select a different port: - port = new Serial(this, Serial.list()[serialPortIndex], 38400); - - // Initialize screen capture code for the display's dimensions. - if(useFullScreenCaps == false) ledBounds = new Rectangle[leds.length]; - ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - gd = ge.getScreenDevices(); - - try { - bot = new Robot(gd[screenNumber]); - } - catch(AWTException e) { - System.out.println("new Robot() failed"); - exit(); - } - gc = gd[screenNumber].getConfigurations(); - dispBounds = gc[0].getBounds(); - dispBounds.x = dispBounds.y = 0; - preview = createImage(5, 5, RGB); - preview.loadPixels(); - - // Precompute locations of every pixel to read when downsampling. - // Saves a bunch of math on each frame, at the expense of a chunk - // of RAM. Number of samples is now fixed at 256; this allows for - // some crazy optimizations in the downsampling code. - for(i=0; i> 8); // LED count high byte - serialData[4] = (byte)((leds.length - 1) & 0xff); // LED count low byte - serialData[5] = (byte)(serialData[3] ^ serialData[4] ^ 0x55); // Checksum - - // Pre-compute gamma correction table for LED brightness levels: - for(i=0; i<256; i++) { - f = pow((float)i / 255.0, 2.8); - gamma[i][0] = (byte)(f * 255.0 + 0.5); - gamma[i][1] = (byte)(f * 240.0 + 0.5); - gamma[i][2] = (byte)(f * 220.0 + 0.5); - } -} - -// PER_FRAME PROCESSING ------------------------------------------------------ - -void draw () { - BufferedImage img; - int i, j, o, c, weight, rb, g, sum, deficit, s2; - int[] pxls, offs; - - if(useFullScreenCaps == true ) { - img = bot.createScreenCapture(dispBounds); - // Get location of source pixel data - screenData = - ((DataBufferInt)img.getRaster().getDataBuffer()).getData(); - } - - weight = 257 - fade; // 'Weighting factor' for new frame vs. old - j = 6; // Serial led data follows header / magic word - - // This computes a single pixel value filtered down from a rectangular - // section of the screen. While it would seem tempting to use the native - // image scaling in Processing/Java, in practice this didn't look very - // good -- either too pixelated or too blurry, no happy medium. So - // instead, a "manual" downsampling is done here. In the interest of - // speed, it doesn't actually sample every pixel within a block, just - // a selection of 256 pixels spaced within the block...the results still - // look reasonably smooth and are handled quickly enough for video. - - for(i=0; i> 24) & 0xff) * weight + - prevColor[i][0] * fade) >> 8); - ledColor[i][1] = (short)(((( g >> 16) & 0xff) * weight + - prevColor[i][1] * fade) >> 8); - ledColor[i][2] = (short)((((rb >> 8) & 0xff) * weight + - prevColor[i][2] * fade) >> 8); - // Boost pixels that fall below the minimum brightness - sum = ledColor[i][0] + ledColor[i][1] + ledColor[i][2]; - if(sum < minBrightness) { - if(sum == 0) { // To avoid divide-by-zero - deficit = minBrightness / 3; // Spread equally to R,G,B - ledColor[i][0] += deficit; - ledColor[i][1] += deficit; - ledColor[i][2] += deficit; - } else { - deficit = minBrightness - sum; - s2 = sum * 2; - // Spread the "brightness deficit" back into R,G,B in proportion to - // their individual contribition to that deficit. Rather than simply - // boosting all pixels at the low end, this allows deep (but saturated) - // colors to stay saturated...they don't "pink out." - ledColor[i][0] += deficit * (sum - ledColor[i][0]) / s2; - ledColor[i][1] += deficit * (sum - ledColor[i][1]) / s2; - ledColor[i][2] += deficit * (sum - ledColor[i][2]) / s2; - } - } - - // Apply gamma curve and place in serial output buffer - serialData[j++] = gamma[ledColor[i][0]][0]; - serialData[j++] = gamma[ledColor[i][1]][1]; - serialData[j++] = gamma[ledColor[i][2]][2]; - // Update pixels in preview image - preview.pixels[leds[i][1] * 5 + leds[i][0]] = 0xFF000000 | - (ledColor[i][0] << 16) | (ledColor[i][1] << 8) | ledColor[i][2]; - } - - if(port != null) port.write(serialData); // Issue data to Arduino - - // Show live preview image - preview.updatePixels(); - scale(40); - image(preview, 0, 0); - - println(frameRate); // How are we doing? - - // Copy LED color data to prior frame array for next pass - arraycopy(ledColor, 0, prevColor, 0, ledColor.length); -} - -// CLEANUP ------------------------------------------------------------------- - -// The DisposeHandler is called on program exit (but before the Serial library -// is shutdown), in order to turn off the LEDs (reportedly more reliable than -// stop()). Seems to work for the window close box and escape key exit, but -// not the 'Quit' menu option. Thanks to phi.lho in the Processing forums. - -void dispose() { - // Fill serialData (after header) with 0's, and issue to Arduino... - java.util.Arrays.fill(serialData, 6, serialData.length, (byte)0); - if(port != null) port.write(serialData); -} \ No newline at end of file diff --git a/Processing/Colorswirl/Colorswirl.pde b/Processing/Colorswirl/Colorswirl.pde deleted file mode 100644 index 752ee60..0000000 --- a/Processing/Colorswirl/Colorswirl.pde +++ /dev/null @@ -1,141 +0,0 @@ -// "Colorswirl" LED demo. This is the host PC-side code written in -// Processing; intended for use with a USB-connected Arduino microcontroller -// running the accompanying LED streaming code. Requires one strand of -// Digital RGB LED Pixels (Adafruit product ID #322, specifically the newer -// WS2801-based type, strand of 25) and a 5 Volt power supply (such as -// Adafruit #276). You may need to adapt the code and the hardware -// arrangement for your specific configuration. - -// -------------------------------------------------------------------- -// This file is part of Adalight. - -// Adalight is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. - -// Adalight is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. - -// You should have received a copy of the GNU Lesser General Public -// License along with Adalight. If not, see -// . -// -------------------------------------------------------------------- - -import processing.serial.*; - -int N_LEDS = 25; // Max of 65536 - -void setup() -{ - byte[] buffer = new byte[6 + N_LEDS * 3]; - Serial myPort; - int i, hue1, hue2, bright, lo, r, g, b, t, prev, frame = 0; - long totalBytesSent = 0; - float sine1, sine2; - - noLoop(); - - // Assumes the Arduino is the first/only serial device. If this is not the - // case, change the device index here. println(Serial.list()); can be used - // to get a list of available serial devices. - myPort = new Serial(this, Serial.list()[0], 115200); - - // A special header / magic word is expected by the corresponding LED - // streaming code running on the Arduino. This only needs to be initialized - // once because the number of LEDs remains constant: - buffer[0] = 'A'; // Magic word - buffer[1] = 'd'; - buffer[2] = 'a'; - buffer[3] = byte((N_LEDS - 1) >> 8); // LED count high byte - buffer[4] = byte((N_LEDS - 1) & 0xff); // LED count low byte - buffer[5] = byte(buffer[3] ^ buffer[4] ^ 0x55); // Checksum - - sine1 = 0.0; - hue1 = 0; - prev = second(); // For bandwidth statistics - - for (;;) { - sine2 = sine1; - hue2 = hue1; - - // Start at position 6, after the LED header/magic word - for (i = 6; i < buffer.length; ) { - // Fixed-point hue-to-RGB conversion. 'hue2' is an integer in the - // range of 0 to 1535, where 0 = red, 256 = yellow, 512 = green, etc. - // The high byte (0-5) corresponds to the sextant within the color - // wheel, while the low byte (0-255) is the fractional part between - // the primary/secondary colors. - lo = hue2 & 255; - switch((hue2 >> 8) % 6) { - case 0: - r = 255; - g = lo; - b = 0; - break; - case 1: - r = 255 - lo; - g = 255; - b = 0; - break; - case 2: - r = 0; - g = 255; - b = lo; - break; - case 3: - r = 0; - g = 255 - lo; - b = 255; - break; - case 4: - r = lo; - g = 0; - b = 255; - break; - default: - r = 255; - g = 0; - b = 255 - lo; - break; - } - - // Resulting hue is multiplied by brightness in the range of 0 to 255 - // (0 = off, 255 = brightest). Gamma corrrection (the 'pow' function - // here) adjusts the brightness to be more perceptually linear. - bright = int(pow(0.5 + sin(sine2) * 0.5, 2.8) * 255.0); - buffer[i++] = byte((r * bright) / 255); - buffer[i++] = byte((g * bright) / 255); - buffer[i++] = byte((b * bright) / 255); - - // Each pixel is slightly offset in both hue and brightness - hue2 += 40; - sine2 += 0.3; - } - - // Slowly rotate hue and brightness in opposite directions - hue1 = (hue1 + 4) % 1536; - sine1 -= .03; - - // Issue color data to LEDs and keep track of the byte and frame counts - myPort.write(buffer); - totalBytesSent += buffer.length; - frame++; - - // Update statistics once per second - if ((t = second()) != prev) { - print("Average frames/sec: "); - print(int((float)frame / (float)millis() * 1000.0)); - print(", bytes/sec: "); - println(int((float)totalBytesSent / (float)millis() * 1000.0)); - prev = t; - } - } -} - -void draw() -{ -} -