SHARE
TWEET

Adalight protocol for FastLED library

a guest Mar 3rd, 2014 3,374 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Slightly modified Adalight protocol implementation that uses FastLED
  2. // library (http://fastled.io) for driving WS2811/WS2812 led stripe
  3. // Was tested only with Prismatik software from Lightpack project
  4.  
  5. #include "FastLED.h"
  6.  
  7. #define NUM_LEDS 94 // Max LED count
  8. #define LED_PIN 12 // arduino output pin
  9. #define GROUND_PIN 10
  10. #define BRIGHTNESS 96 // maximum brightness
  11. #define SPEED 115200 // virtual serial port speed, must be the same in boblight_config
  12.  
  13. CRGB leds[NUM_LEDS];
  14. uint8_t * ledsRaw = (uint8_t *)leds;
  15.  
  16. // A 'magic word' (along with LED count & checksum) precedes each block
  17. // of LED data; this assists the microcontroller in syncing up with the
  18. // host-side software and properly issuing the latch (host I/O is
  19. // likely buffered, making usleep() unreliable for latch).  You may see
  20. // an initial glitchy frame or two until the two come into alignment.
  21. // The magic word can be whatever sequence you like, but each character
  22. // should be unique, and frequent pixel values like 0 and 255 are
  23. // avoided -- fewer false positives.  The host software will need to
  24. // generate a compatible header: immediately following the magic word
  25. // are three bytes: a 16-bit count of the number of LEDs (high byte
  26. // first) followed by a simple checksum value (high byte XOR low byte
  27. // XOR 0x55).  LED data follows, 3 bytes per LED, in order R, G, B,
  28. // where 0 = off and 255 = max brightness.
  29.  
  30. static const uint8_t magic[] = {'A','d','a'};
  31. #define MAGICSIZE  sizeof(magic)
  32. #define HEADERSIZE (MAGICSIZE + 3)
  33.  
  34. #define MODE_HEADER 0
  35. #define MODE_DATA   2
  36.  
  37. // If no serial data is received for a while, the LEDs are shut off
  38. // automatically.  This avoids the annoying "stuck pixel" look when
  39. // quitting LED display programs on the host computer.
  40. static const unsigned long serialTimeout = 150000; // 150 seconds
  41.  
  42. void setup()
  43. {
  44.   pinMode(GROUND_PIN, OUTPUT);
  45.   digitalWrite(GROUND_PIN, LOW);
  46.   FastLED.addLeds<WS2811, LED_PIN, BRG>(leds, NUM_LEDS);
  47.  
  48.   // Dirty trick: the circular buffer for serial data is 256 bytes,
  49.   // and the "in" and "out" indices are unsigned 8-bit types -- this
  50.   // much simplifies the cases where in/out need to "wrap around" the
  51.   // beginning/end of the buffer.  Otherwise there'd be a ton of bit-
  52.   // masking and/or conditional code every time one of these indices
  53.   // needs to change, slowing things down tremendously.
  54.   uint8_t
  55.     buffer[256],
  56.     indexIn       = 0,
  57.     indexOut      = 0,
  58.     mode          = MODE_HEADER,
  59.     hi, lo, chk, i, spiFlag;
  60.   int16_t
  61.     bytesBuffered = 0,
  62.     hold          = 0,
  63.     c;
  64.   int32_t
  65.     bytesRemaining;
  66.   unsigned long
  67.     startTime,
  68.     lastByteTime,
  69.     lastAckTime,
  70.     t;
  71.   int32_t outPos = 0;
  72.  
  73.   Serial.begin(SPEED); // Teensy/32u4 disregards baud rate; is OK!
  74.  
  75.   Serial.print("Ada\n"); // Send ACK string to host
  76.  
  77.   startTime    = micros();
  78.   lastByteTime = lastAckTime = millis();
  79.  
  80.   // loop() is avoided as even that small bit of function overhead
  81.   // has a measurable impact on this code's overall throughput.
  82.  
  83.   for(;;) {
  84.  
  85.     // Implementation is a simple finite-state machine.
  86.     // Regardless of mode, check for serial input each time:
  87.     t = millis();
  88.     if((bytesBuffered < 256) && ((c = Serial.read()) >= 0)) {
  89.       buffer[indexIn++] = c;
  90.       bytesBuffered++;
  91.       lastByteTime = lastAckTime = t; // Reset timeout counters
  92.     } else {
  93.       // No data received.  If this persists, send an ACK packet
  94.       // to host once every second to alert it to our presence.
  95.       if((t - lastAckTime) > 1000) {
  96.         Serial.print("Ada\n"); // Send ACK string to host
  97.         lastAckTime = t; // Reset counter
  98.       }
  99.       // If no data received for an extended time, turn off all LEDs.
  100.       if((t - lastByteTime) > serialTimeout) {
  101.         memset(leds, 0,  NUM_LEDS * sizeof(struct CRGB)); //filling Led array by zeroes
  102.         FastLED.show();
  103.         lastByteTime = t; // Reset counter
  104.       }
  105.     }
  106.  
  107.     switch(mode) {
  108.  
  109.      case MODE_HEADER:
  110.  
  111.       // In header-seeking mode.  Is there enough data to check?
  112.       if(bytesBuffered >= HEADERSIZE) {
  113.         // Indeed.  Check for a 'magic word' match.
  114.         for(i=0; (i<MAGICSIZE) && (buffer[indexOut++] == magic[i++]););
  115.         if(i == MAGICSIZE) {
  116.           // Magic word matches.  Now how about the checksum?
  117.           hi  = buffer[indexOut++];
  118.           lo  = buffer[indexOut++];
  119.           chk = buffer[indexOut++];
  120.           if(chk == (hi ^ lo ^ 0x55)) {
  121.             // Checksum looks valid.  Get 16-bit LED count, add 1
  122.             // (# LEDs is always > 0) and multiply by 3 for R,G,B.
  123.             bytesRemaining = 3L * (256L * (long)hi + (long)lo + 1L);
  124.             bytesBuffered -= 3;
  125.             outPos = 0;
  126.             memset(leds, 0,  NUM_LEDS * sizeof(struct CRGB));
  127.             mode           = MODE_DATA; // Proceed to latch wait mode
  128.           } else {
  129.             // Checksum didn't match; search resumes after magic word.
  130.             indexOut  -= 3; // Rewind
  131.           }
  132.         } // else no header match.  Resume at first mismatched byte.
  133.         bytesBuffered -= i;
  134.       }
  135.       break;
  136.  
  137.      case MODE_DATA:
  138.  
  139.       if(bytesRemaining > 0) {
  140.         if(bytesBuffered > 0) {
  141.           if (outPos < sizeof(leds))
  142.             ledsRaw[outPos++] = buffer[indexOut++];   // Issue next byte
  143.           bytesBuffered--;
  144.           bytesRemaining--;
  145.         }
  146.         // If serial buffer is threatening to underrun, start
  147.         // introducing progressively longer pauses to allow more
  148.         // data to arrive (up to a point).
  149.       } else {
  150.         // End of data -- issue latch:
  151.         startTime  = micros();
  152.         mode       = MODE_HEADER; // Begin next header search
  153.         FastLED.show();
  154.       }
  155.     } // end switch
  156.   } // end for(;;)
  157. }
  158.  
  159. void loop()
  160. {
  161.   // Not used.  See note in setup() function.
  162. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top