Adalight idle time lighting

EL Wire/Tape/Panels, LEDs, pixels and strips, LCDs and TFTs, etc products from Adafruit

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
-dus-
 
Posts: 6
Joined: Fri Mar 01, 2013 9:18 am

Adalight idle time lighting

Post by -dus- »

Hi, I hope someone can help me with editing the original Ledstream.pde file.

When my girlfriend and I are watching TV our HTPC is either idle, or turned off, which means the ambilight doesn't work either. If so, we always have two small lamps next to our TV burning at night. However, these lamps are blocking a part of the ambilight when we have our media PC turned on. So I was wondering if I could simulate the same (or similair) light when our HTPC is idle or turned off?

With the original file:

- Turning on powersupply Arduino/LED's: No reaction (although sometimes the R/G/B test script runs, even with the HTPC turned off)
- Power on HTPC : The arduino runs the R/G/B test script as soon as communication is detected.
- Start up Ambibox : The ambilight system works normally
- HTPC powered off or Idle : No communication, so the arduino disables the LED's after 15 sec.

What I would like to have when there is no USB communication (PC off or idle):

- Turning on powersupply Arduino/LED's: The adruino turns on all LED's, and set's them to a predetermined color and strenght (defined later on)
- Power on HTPC : The arduino runs the R/G/B test script as soon as communication is detected (so no changes).
- Start up Ambibox : The ambilight system works normally (so no changes).
- HTPC powered off or Idle : No communication; The arduino sets al LED's back to the predetermined color and strenght after a few seconds.

So basicly idle = standard color/strenght.

Ik hope I'm making sense :wink:

I hope someone can help me with this!

Thanks!

User avatar
pburgess
 
Posts: 4161
Joined: Sun Oct 26, 2008 2:29 am

Re: Adalight idle time lighting

Post by pburgess »

This would all be done in the 'LEDstream' code on the Arduino.

First, just above the setup() function, create a table containing the colors for all the LEDs in their idle state. Might look something like this:

Code: Select all

const uint8_t idleColors[] = {
  0, 0, 0, // Red, green, blue colors for first LED in strand
  0, 0, 0, // RGB for second LED
  255, 255, 255, // Third
  [ list continues for as many LEDs in strand, always 3 numbers per LED ]
  0, 0, 0 // Last LED
}
To set the LEDs to the idle colors, the following code can be used:

Code: Select all

for(uint16_t foo=0; foo<sizeof(idleColors); foo++) {
  for(SPDR=idleColors[foo]; !(SPSR & _BV(SPIF)); );
}
delay(1);
Copy that latter section of code to two places: first one right after this:

Code: Select all

Serial.print("Ada\n"); // Send ACK string to host
and the second would replace these lines later in the code:

Code: Select all

        for(c=0; c<32767; c++) {
          for(SPDR=0; !(SPSR & _BV(SPIF)); );
        }
        delay(1); // One millisecond pause = latch

User avatar
-dus-
 
Posts: 6
Joined: Fri Mar 01, 2013 9:18 am

Re: Adalight idle time lighting

Post by -dus- »

Hi,

Thanks for your answer. Could you please check the below comments?
First, just above the setup() function, create a table containing the colors for all the LEDs in their idle state.
So add the code above the void setup() as shown below? I Have a 100 LED setup. so I have to add the correct RGB code 100x in the below code?

Code: Select all

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

const uint8_t idleColors[] = {
  0, 0, 0, // Red, green, blue colors for first LED in strand
  0, 0, 0, // RGB for second LED
  255, 255, 255, // Third
  [ list continues for as many LEDs in strand, always 3 numbers per LED ]
  0, 0, 0 // Last LED
}

void setup()
{
  // Dirty trick: the circular buffer for serial data is 256 bytes,
Copy that latter section of code to two places: first one right after this:
I found the Serial.print("Ada\n"); // Send ACK string to host string twice in the code. Not sure which one to use:

Code: Select all

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(uint16_t foo=0; foo<sizeof(idleColors); foo++) {
          for(SPDR=idleColors[foo]; !(SPSR & _BV(SPIF)); );
        }
        delay(1);
        lastByteTime = t; // Reset counter
      }
    }
and the second would replace these lines later in the code:
So like this?

Code: Select all

    // 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(uint16_t foo=0; foo<sizeof(idleColors); foo++) {
          for(SPDR=idleColors[foo]; !(SPSR & _BV(SPIF)); );
        }
        delay(1);
        lastByteTime = t; // Reset counter
I'm really not a coder, so If I made a mistake, would it be possible for you to apply the changes to the coplete code, and attach it in this topic?

Thanks!

User avatar
pburgess
 
Posts: 4161
Joined: Sun Oct 26, 2008 2:29 am

Re: Adalight idle time lighting

Post by pburgess »

-DUS- wrote:So add the code above the void setup() as shown below? I Have a 100 LED setup. so I have to add the correct RGB code 100x in the below code?
There would be one table containing 100 lines, each line containing three numbers (red, green and blue), separated by commas.
I found the Serial.print("Ada\n"); // Send ACK string to host string twice in the code. Not sure which one to use
Sorry. Put it after the first one.
So like this?
Exactly, yep.
I'm really not a coder, so If I made a mistake, would it be possible for you to apply the changes to the coplete code, and attach it in this topic?
Give it a try (or two) first. If it doesn't work, you can always fetch the original code off Github again.

User avatar
-dus-
 
Posts: 6
Joined: Fri Mar 01, 2013 9:18 am

Re: Adalight idle time lighting

Post by -dus- »

Hi,

Thanks for your help so far, I really appreciate it! :D

I've made the changes to the code, but when trying to complile it gives me the below error:

LEDstream:190: error: expected ',' or ';' before 'void'

I've added the modified code below, could you please check?

Code: Select all

// 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 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
//   <http://www.gnu.org/licenses/>.
// --------------------------------------------------------------------

#include <SPI.h>

// 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

const uint8_t idleColors[] = {
  255, 235, 100, // Red, green, blue colors for first LED in strand
  255, 235, 100, // RGB for second LED
  255, 235, 100, // Third
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100,
  255, 235, 100 //last led
}

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
    for(uint16_t foo=0; foo<sizeof(idleColors); foo++) {
      for(SPDR=idleColors[foo]; !(SPSR & _BV(SPIF)); );
    }
    delay(1);

  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(uint16_t foo=0; foo<sizeof(idleColors); foo++) {
          for(SPDR=idleColors[foo]; !(SPSR & _BV(SPIF)); );
        }
        delay(1);
        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<MAGICSIZE) && (buffer[indexOut++] == magic[i++]););
        if(i == MAGICSIZE) {
          // Magic word matches.  Now how about the checksum?
          hi  = buffer[indexOut++];
          lo  = buffer[indexOut++];
          chk = buffer[indexOut++];
          if(chk == (hi ^ lo ^ 0x55)) {
            // Checksum looks valid.  Get 16-bit LED count, add 1
            // (# LEDs is always > 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.
}
Thanks!

juppk
 
Posts: 4
Joined: Fri Aug 30, 2013 10:19 am

Re: Adalight idle time lighting

Post by juppk »

As the compiler mentioned: you forgot a ';' at the end of the RGB array.

Code: Select all

 
255, 235, 100 //last led
};

void setup()

Locked
Please be positive and constructive with your questions and comments.

Return to “Glowy things (LCD, LED, TFT, EL) purchased at Adafruit”