Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Work-in-progress Adafruit DotStar port of the Actinic ArduinoController, demonstrating serial baud rate issues
// 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
You can’t perform that action at this time.