#define RED_LED 5 #define GREEN_LED 3 #define BLUE_LED 6 #define STATUS_LED 4 #define MAX_NUMBER_DIGITS 4 using namespace std; int tps = 33; unsigned long current_ms = millis(); unsigned long tick_interval_tracker = 0; unsigned int tick_interval = 1000 / tps; int leds[] = {RED_LED, GREEN_LED, BLUE_LED}; int led_iterator = 0; int mode = 0; // 0 = breathe, 1 = set color float current_vals[] = {0, 0, 0}; int breathe_increments[] = {1, 2, 4}; int breathe_directions[] = {0, 0, 0}; int target_vals[] = {0, 0, 0}; int fade_ticks = 0; int fade_ms = 0; float fade_increments[] = {0, 0, 0}; char current_char = ' '; char command = ' '; char arg = ' '; char current_number_string[MAX_NUMBER_DIGITS + 1]; int position = 0; int current_number_len = 0; int parsed_number = 0; bool end_of_line = 0; void setup() { Serial.begin(9600); Serial.println("ready."); pinMode(RED_LED, OUTPUT); pinMode(GREEN_LED, OUTPUT); pinMode(BLUE_LED, OUTPUT); pinMode(STATUS_LED, OUTPUT); reset_number_string(); } void loop() { if (Serial.available()) { current_char = Serial.read(); if (position == 0) { switch (current_char) { case 'F': case 'T': case 'B': command = current_char; break; default: Serial.println("invalid command."); Serial.flush(); command = arg = ' '; position = parsed_number = 0; reset_number_string(); break; } } else { switch (current_char) { case '0' ... '9': if (current_number_len < MAX_NUMBER_DIGITS) { current_number_len++; current_number_string[current_number_len - 1] = current_char; } break; case 'R': case 'G': case 'B': case 'T': case 'I': arg = current_char; break; case ' ': if (current_number_len > 0) parsed_number = atoi(current_number_string); if (arg != ' ') callback(); arg = current_char = ' '; reset_number_string(); break; case '\n': if (current_number_len > 0) parsed_number = atoi(current_number_string); end_of_line = true; callback(); command = arg = ' '; position = parsed_number = 0; reset_number_string(); break; default: Serial.println("invalid syntax."); Serial.flush(); command = arg = ' '; position = parsed_number = 0; reset_number_string(); } } if (current_char == '\n') { end_of_line = false; Serial.println("ok."); } else position++; } if (millis() - tick_interval_tracker >= tick_interval) { tick_interval_tracker += tick_interval; execute_tick(); } } void callback() { switch (command) { case 'B': mode = 0; break; case 'F': switch (arg) { case 'T': fade_ms = parsed_number; break; case 'R': target_vals[0] = parsed_number; break; case 'G': target_vals[1] = parsed_number; break; case 'B': target_vals[2] = parsed_number; break; } if (end_of_line == true) { if (fade_ms <= tick_interval) { mode = 1; fade_ticks = 0; } else { mode = 1; fade_ticks = ceil(fade_ms / (float) tick_interval); led_iterator = 0; while (led_iterator < 3) { fade_increments[led_iterator] = -((current_vals[led_iterator] - target_vals[led_iterator]) / (float) fade_ticks); led_iterator++; } } } break; case 'T': if (arg == 'R') { tps = parsed_number; tick_interval = 1000 / tps; } else if (arg == 'I') { tick_interval = parsed_number; tps = 1000 / tick_interval; } break; } } void reset_number_string() { for (int i = 0; i < MAX_NUMBER_DIGITS; i++) current_number_string[i] = ' '; current_number_string[MAX_NUMBER_DIGITS] = '\0'; current_number_len = 0; } void execute_tick() { if (mode == 0) { led_iterator = 0; while (led_iterator < 3) { if (current_vals[led_iterator] <= 0 || current_vals[led_iterator] >= 255) breathe_increments[led_iterator] = -breathe_increments[led_iterator]; analogWrite(leds[led_iterator], current_vals[led_iterator]); current_vals[led_iterator] = constrain(current_vals[led_iterator] + breathe_increments[led_iterator], 0, 255); led_iterator++; } } else if (mode == 1) { if (fade_ticks > 0) { led_iterator = 0; while (led_iterator < 3) { current_vals[led_iterator] += fade_increments[led_iterator]; analogWrite(leds[led_iterator], current_vals[led_iterator]); led_iterator++; } fade_ticks--; } else if (fade_ticks == 0) { Serial.println("done."); fade_ticks--; } } }