-
-
Save digitalcircuit/ae8c32b132d8648c917730204e983e1a to your computer and use it in GitHub Desktop.
Work-in-progress Adafruit DotStar port of the Actinic ArduinoController, demonstrating serial baud rate issues
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// FIXME: Finish modifications for DotStar, clean up comments, etc! | |
// THIS IS NOT A FINAL VERSION | |
/* Actinic: Compilation of amazing work done by others | |
Some modifications in order to be more useful with the companion C# Actinic program, built | |
by Shane Synan <digitalcircuit36939@gmail.com> | |
-- Added an automatic switch to a test-mode if no serial input is received in an amount of time | |
-- Added a batch-update mode to modify both color and hue at once | |
-- Added output string on startup to identify firmware on Arduino | |
-- Fixed an input overflow issue with Arduino claiming to be ready for new input before finishing the prior command | |
-- Reduced timing delays in G35String.cpp in order to increase performance | |
*/ | |
/* | |
G35: An Arduino library for GE Color Effects G-35 holiday lights. | |
Copyright © 2011 The G35 Authors. Use, modification, and distribution are | |
subject to the BSD license as described in the accompanying LICENSE file. | |
See README for complete attributions. | |
*/ | |
#include <Adafruit_DotStar.h> | |
#include <SPI.h> | |
// Current Arduino protocol version. This must match what Actinic expects for | |
// negotiation to succeed. | |
#define PROTOCOL_VERSION (2.2) | |
// Total # of lights on string (usually 50, 48, or 36). Maximum is 63, because | |
// the protocol uses 6-bit addressing and bulb #63 is reserved for broadcast | |
// messages. | |
#define LIGHT_COUNT (300) | |
// FIXME: Merge lights | |
#define LIGHT_COUNT_DIVIDER (1) | |
// Lighted length of the string. | |
#define STRAND_LENGTH (10.0) | |
// Copied from G35String.cpp since it's not defined in the header - update here if needed | |
#define G35_DELAYLONG 7 // should be ~ 20uS long | |
#define G35_DELAYSHORT 3 // should be ~ 10uS long | |
#define G35_DELAYEND 40 // should be ~ 30uS long | |
// Specifies expected delay in milliseconds to update all lights. | |
// Calculated from the constants defined in G35String.h, with additional delay | |
// added to account for processing time. | |
// | |
// You can measure real latency with Actinic by defining DEBUG_USB_PERFORMANCE in ArduinoOutput.cs | |
// (Below assumes about a factor of four increase for each light - x3.15. It's not quite 3.) | |
const float AVERAGE_LATENCY = 1; /*((G35_DELAYSHORT + (G35_DELAYLONG + G35_DELAYSHORT)*26 + G35_DELAYEND) * 0.001) | |
* LIGHT_COUNT*3.15;*/ | |
// Arduino pin number. Pin 13 will blink the on-board LED. | |
//#define STATUS_PIN (13) | |
//#define G35_PIN (8) | |
//G35String lights(G35_PIN, LIGHT_COUNT); | |
Adafruit_DotStar strip = Adafruit_DotStar(LIGHT_COUNT, DOTSTAR_BGR); | |
// GE Color Effects Arduino Interface | |
// by Tom Lee <thomas.j.lee at gmail.com> | |
// Based on code ported by Scott Harris <scottrharris@gmail.com> | |
// scottrharris.blogspot.com | |
// which was in turn based on : | |
/*! Christmas Light Control | |
** By Robert Quattlebaum <darco@deepdarc.com> | |
** Released November 27th, 2010 | |
** | |
** For more information, | |
** see <http://www.deepdarc.com/2010/11/27/hacking-christmas-lights/>. | |
** | |
** Originally intended for the ATTiny13, but should | |
** be easily portable to other microcontrollers. | |
*/ | |
//#define xmas_color_t uint16_t // typedefs can cause trouble in the Arduino environment | |
//uint16_t light_hue_array[LIGHT_COUNT]; | |
//uint8_t light_intensity_array[LIGHT_COUNT]; | |
//char light_color_array[LIGHT_COUNT * 3]; | |
//uint32_t light_color_array[LIGHT_COUNT]; | |
/*char serial_buffer[120]; | |
const size_t serial_buffer_head = 0; | |
const size_t serial_buffer_tail = 0; | |
const size_t serial_buffer_size = sizeof(serial_buffer); | |
*/ | |
const unsigned int IDLE_TIME = 5 * 1000; | |
unsigned long lastCommandTime = 0; | |
boolean commandSent = false; | |
boolean idleMode = false; | |
boolean changed = false; | |
void setup() { | |
//pinMode(STATUS_PIN, OUTPUT); | |
//pinMode(G35_PIN, OUTPUT); | |
//digitalWrite(STATUS_PIN, LOW); | |
//digitalWrite(G35_PIN, LOW); | |
Serial.begin(115200); | |
//Serial.begin(230400); | |
//Serial.begin(250000); | |
//Serial.begin(921600); | |
//Serial.begin(1000000); | |
//Serial.begin(2000000); | |
strip.begin(); | |
strip.show(); | |
//lights.enumerate(); | |
//lights.fill_color(0, LIGHT_COUNT, G35::MAX_INTENSITY, COLOR_BLACK); | |
//digitalWrite(STATUS_PIN, LOW); | |
// Firmware version and hardware information, used by Actinic to automatically detect controllers | |
// Use F() to use PROGMEM instead of wasting SRAM | |
Serial.print(F("ActinicArduino_Controller:")); | |
Serial.println (PROTOCOL_VERSION); | |
Serial.print(F("light_count:")); | |
// FIXME: Merge lights | |
Serial.println (LIGHT_COUNT / LIGHT_COUNT_DIVIDER); | |
//Serial.println (LIGHT_COUNT); | |
Serial.print(F("strand_length:")); | |
Serial.println (STRAND_LENGTH); | |
Serial.print(F("color_max:")); | |
Serial.println (255); | |
//Serial.println (CHANNEL_MAX); | |
Serial.print(F("bright_max:")); | |
Serial.println (255); | |
//Serial.println (G35::MAX_INTENSITY); | |
Serial.print(F("avg_latency:")); | |
Serial.println (AVERAGE_LATENCY); | |
Serial.println(F("end_init")); | |
} | |
void loop() { | |
if(Serial.available()>0) { | |
// Hue, intensity, or both? | |
char command = Serial.read(); | |
if (command=='I') { | |
//digitalWrite(STATUS_PIN, HIGH); | |
// read the intensity data & assign it | |
for(int i=0;i<LIGHT_COUNT;i++) { | |
while(Serial.available() < 1) { | |
} | |
//light_intensity_array[i] = Serial.read(); | |
Serial.read(); | |
// IGNORED | |
//The (intensity > MAX_INTENSITY) situation is handled by the G35 library | |
} | |
changed = true; | |
commandSent = true; | |
lastCommandTime = millis(); | |
} else if(command=='H') { | |
//digitalWrite(STATUS_PIN, HIGH); | |
//light_color_array | |
/* | |
//char buf[500]; | |
uint8_t *pixels = strip.getPixels(); | |
char buf[90]; | |
int count = 0; | |
int pixel_i = 0; | |
int n = 0; | |
const int BUF_BYTES = sizeof(buf); | |
while (pixel_i < LIGHT_COUNT) { | |
while (count < BUF_BYTES) { | |
n = Serial.readBytes(buf + count, BUF_BYTES - count); | |
if (n == 0) { | |
while (!Serial.available()) ; // wait | |
} | |
count += n; | |
} | |
for (uint8_t i = 0; i < count; ++i) { | |
pixels[i] | |
UInt32 combined = (UInt32)((map[i] << 32) | (map[i+1] << 24) | (map[i+2] << 16) | (map[i+3] << 8)); | |
} | |
total_count += count; | |
} | |
*/ | |
/* | |
const int buf_size = 360; | |
char buf[buf_size]; | |
int count=0; | |
int total_count = (LIGHT_COUNT * 3) / buf_size; | |
int n; | |
// receive 500 bytes, using Serial.readBytes | |
// as many times as necessary until all 500 | |
while (count < total_count) { | |
while (count < buf_size) { | |
n = Serial.readBytes(buf+count, buf_size - count); | |
if (n == 0) { | |
while (!Serial.available()) ; // wait | |
} | |
count = count + n; | |
} | |
total_count += count; | |
} | |
*/ | |
/* | |
int bytes_read; | |
while (bytes_read < LIGHT_COUNT*3) { | |
if (Serial.read() != -1) { | |
++bytes_read; | |
} | |
Serial.print(bytes_read); | |
} | |
*/ | |
// read the hue data and assign it | |
for(int i=0;i<(LIGHT_COUNT);i++) { | |
while(Serial.available() < 3) { | |
} | |
//light_hue_array[i] = G35::color(Serial.read(), Serial.read(), Serial.read()); | |
strip.setPixelColor(i, strip.gamma8(Serial.read()), strip.gamma8(Serial.read()), strip.gamma8(Serial.read())); | |
// FIXME: Merge lights | |
for(int i_plus=i+1; i_plus < (i+LIGHT_COUNT_DIVIDER); i_plus++) { | |
strip.setPixelColor(i_plus, strip.getPixelColor(i)); | |
} | |
i = i + (LIGHT_COUNT_DIVIDER - 1); | |
} | |
changed = true; | |
commandSent = true; | |
lastCommandTime = millis(); | |
} else if(command=='A') { | |
//digitalWrite(STATUS_PIN, HIGH); | |
// read the color and hue data, then assign it | |
for(int i=0;i<(LIGHT_COUNT);i++) { | |
while(Serial.available() < 4) { | |
} | |
//light_hue_array[i] = G35::color(Serial.read(), Serial.read(), Serial.read()); | |
strip.setPixelColor(i, strip.gamma8(Serial.read()), strip.gamma8(Serial.read()), strip.gamma8(Serial.read())); | |
// FIXME: Merge lights | |
for(int i_plus=i+1; i_plus < (i+LIGHT_COUNT_DIVIDER); i_plus++) { | |
strip.setPixelColor(i_plus, strip.getPixelColor(i)); | |
} | |
i = i + (LIGHT_COUNT_DIVIDER - 1); | |
//light_intensity_array[i] = Serial.read(); | |
Serial.read(); | |
// IGNORED | |
} | |
changed = true; | |
commandSent = true; | |
lastCommandTime = millis(); | |
} | |
} | |
if(changed) { | |
//xmas_reflect_array(light_hue_array, light_intensity_array); | |
strip.show(); | |
Serial.println('#'); | |
// Shane: don't acknowledge the write until the LEDs have been updated | |
//digitalWrite(STATUS_PIN, LOW); | |
changed = false; | |
} | |
if (commandSent == false) { | |
if ((millis() - lastCommandTime) > IDLE_TIME) { | |
if (idleMode == false) { | |
idleMode = true; | |
//digitalWrite(STATUS_PIN, HIGH); | |
/*for (int selectedBrightness = 0; selectedBrightness <= G35::MAX_INTENSITY; selectedBrightness += 3) { | |
for (uint16_t index = 0; index < LIGHT_COUNT; ++index) { | |
strip.setPixelColor(index, 255, 128, 0); | |
} | |
strip.setPixelColor(i, Serial.read(), Serial.read(), Serial.read()); | |
strip.show(); | |
}*/ | |
//lights.do_test_patterns(); | |
//lights.fill_color(0, LIGHT_COUNT, G35::MAX_INTENSITY, COLOR_ORANGE); | |
for (int dim = 255; dim > 0; dim -= 1) { | |
for (uint16_t index = 0; index < LIGHT_COUNT; ++index) { | |
strip.setPixelColor(index, strip.gamma8(255 - dim), strip.gamma8(128 - (dim / 2)), strip.gamma8(0)); | |
} | |
strip.show(); | |
delay(5); | |
} | |
//lights.set_color(0, G35::MAX_INTENSITY, COLOR_RED); | |
strip.setPixelColor(0, 255, 0, 0); | |
//lights.set_color(1, G35::MAX_INTENSITY, COLOR_YELLOW); | |
strip.setPixelColor(1, 255, 255, 0); | |
//lights.set_color((LIGHT_COUNT / 2) - 2, G35::MAX_INTENSITY, COLOR_YELLOW); | |
strip.setPixelColor((LIGHT_COUNT / 2) - 2, 255, 255, 0); | |
//lights.set_color((LIGHT_COUNT / 2) - 1, G35::MAX_INTENSITY, COLOR_PURPLE); | |
strip.setPixelColor((LIGHT_COUNT / 2) - 1, 0, 255, strip.gamma8(128)); | |
//lights.set_color((LIGHT_COUNT / 2), G35::MAX_INTENSITY, COLOR_BLUE); | |
strip.setPixelColor((LIGHT_COUNT / 2), 0, 0, 255); | |
//lights.set_color((LIGHT_COUNT / 2) + 1, G35::MAX_INTENSITY, COLOR_YELLOW); | |
strip.setPixelColor((LIGHT_COUNT / 2), 255, 255, 0); | |
//lights.set_color(LIGHT_COUNT - 2, G35::MAX_INTENSITY, COLOR_YELLOW); | |
strip.setPixelColor(LIGHT_COUNT - 2, 255, 255, 0); | |
//lights.set_color(LIGHT_COUNT - 1, G35::MAX_INTENSITY, COLOR_GREEN); | |
strip.setPixelColor(LIGHT_COUNT - 1, 0, 255, 0); | |
//digitalWrite(STATUS_PIN, LOW); | |
strip.show(); | |
} | |
} | |
if (commandSent == true & idleMode == true) { | |
idleMode = false; | |
} | |
} | |
interrupts(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment