-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathActinicArduino.ino
174 lines (152 loc) · 5.92 KB
/
ActinicArduino.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/**
* ActinicArduino: generic LED controller program, designed for use with the
* companion C# program Actinic.
*
* @author Shane Synan <[email protected]>
*/
// --------
// README:
// Set up your own hardware (LED devices, status LED, etc) in the
// "device_config.h" file. You shouldn't need to modify anything here.
// General
#include "color.h"
#include "outputabstract.h"
#include "protocol.h"
#include "statusabstract.h"
#include "statecontroller.h"
// Output and board configuration
#include "device_config.h"
// Set up global peripherals (controlled by "device_config.h")
DEC_OUTPUT ///< Declaration of output device
DEC_STATUS ///< Declaration of status device
/// System state machine and events processor
StateController controller(BUTTON_PIN, &statusLed, &lights);
bool commandSent = false; ///< If a command was sent this loop iteration
bool outputInvalidated = false; ///< If output was changed and needs updated
/**
* Setup the firmware and peripherals
*/
void setup()
{
// Initialize to the fastest common serial baud rate
Serial.begin(115200);
// Initialize lights and fill with black
lights.initialize();
lights.fillColor(sCRGB(0, 0, 0));
lights.show();
}
/**
* Main loop to process commands, events, and generate output
*/
void loop()
{
// Check for pending commands
if (Serial.available() > 0) {
// First byte is the command
char command = Serial.read();
// Set aside storage for LED commands
const size_t serial_buffer_size_max = 4;
char serial_buffer[serial_buffer_size_max];
// Mark command as sent
commandSent = true;
if (command == '\n') {
// Ignore newlines
} else if (command == Protocol::Command::QUERY_INFO) {
// Query for info
Protocol::print_header();
} else if (command == Protocol::Command::SET_BRIGHTNESS) {
// Set brightness
statusLed.setBusy(true);
// Store incoming data in a 1 byte buffer
const size_t bright_data_size = 1;
static_assert(
bright_data_size <= serial_buffer_size_max,
"bright_data_size larger than serial_buffer_size_max"
);
// Read data in, 1 pixel at a time, and assign it
for (int i = 0; i < LIGHT_COUNT; ++i) {
if (Serial.readBytes(serial_buffer, bright_data_size) == 0) {
// Timeout, cancel (partial changes kept)
Serial.println(PROTOCOL_MSG_TIMEOUT);
break;
}
// Set pixel brightness
lights.setBrightness(i, serial_buffer[0]);
}
// Mark output as needing refreshed
outputInvalidated = true;
} else if (command == Protocol::Command::SET_COLOR
|| command == Protocol::Command::SET_HUE) {
// Set color, resetting or keeping brightness (via COLOR or HUE)
statusLed.setBusy(true);
// Store incoming data in a 3 byte buffer
const size_t rgb_data_size = 3;
static_assert(
rgb_data_size <= serial_buffer_size_max,
"rgb_data_size larger than serial_buffer_size_max"
);
bool preserveBrightness =
(command == Protocol::Command::SET_HUE);
// Read data in, 1 pixel at a time, and assign it
for (int i = 0; i < LIGHT_COUNT; ++i) {
if (Serial.readBytes(serial_buffer, rgb_data_size) == 0) {
// Timeout, cancel (partial changes kept)
Serial.println(PROTOCOL_MSG_TIMEOUT);
break;
}
if (preserveBrightness) {
// Set pixel color, preserving existing brightness
lights.setHue(i,
sCRGB(serial_buffer[2], serial_buffer[1], serial_buffer[0]));
} else {
// Set pixel color, resetting brightness
lights.setColor(i,
sCRGB(serial_buffer[2], serial_buffer[1], serial_buffer[0]));
}
}
// Mark output as needing refreshed
outputInvalidated = true;
} else if (command == Protocol::Command::SET_ALL) {
// Set brightness and color
statusLed.setBusy(true);
// Store incoming data in a 4 byte buffer
const size_t rgba_data_size = 4;
static_assert(
rgba_data_size <= serial_buffer_size_max,
"rgba_data_size larger than serial_buffer_size_max"
);
// Read data in, 1 pixel at a time, and assign it
for (int i = 0; i < LIGHT_COUNT; ++i) {
if (Serial.readBytes(serial_buffer, rgba_data_size) == 0) {
// Timeout, cancel (partial changes kept)
Serial.println(PROTOCOL_MSG_TIMEOUT);
break;
}
// Set pixel brightness and color
lights.setColor(i,
sCRGB(serial_buffer[2], serial_buffer[1], serial_buffer[0]), serial_buffer[3]);
}
// Mark output as needing refreshed
outputInvalidated = true;
} else {
// Unknown command
Serial.println(PROTOCOL_MSG_UNKNOWN_CMD);
}
}
// Process button events, state, etc
controller.processEvents();
if (commandSent == true) {
// Tell the state controller a command's been received
controller.markLinked();
commandSent = false;
}
if (outputInvalidated) {
// Send the updates to the lights
lights.show();
// Acknowledge the command (only after lights have updated)
Serial.println(Protocol::Reply::FINISHED);
// Clear status
statusLed.setBusy(false);
outputInvalidated = false;
}
}