2015-10-26 19:39:13 +01:00
|
|
|
// Takes commands over serial and updates a NeoPixel LED ring.
|
|
|
|
//
|
2015-12-31 10:20:50 +01:00
|
|
|
// Copyright 2015 Google Inc.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
2015-10-25 22:06:31 +01:00
|
|
|
#include <avr/interrupt.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "neopixel.h"
|
|
|
|
#include "serial.h"
|
|
|
|
|
2015-12-31 10:34:34 +01:00
|
|
|
/// Main application class.
|
|
|
|
///
|
|
|
|
/// Reads commands from the serial port, processes them, and
|
|
|
|
/// responds.
|
|
|
|
///
|
2015-10-26 19:39:13 +01:00
|
|
|
class Ser2Neo {
|
|
|
|
public:
|
|
|
|
void init();
|
|
|
|
void run();
|
2015-10-25 22:06:31 +01:00
|
|
|
|
2015-10-26 19:39:13 +01:00
|
|
|
private:
|
|
|
|
static const uint8_t EOF = '\r';
|
|
|
|
static const uint8_t ESC = '+';
|
2015-10-25 22:06:31 +01:00
|
|
|
|
2015-10-26 19:39:13 +01:00
|
|
|
int read_escaped();
|
|
|
|
void read_leds();
|
|
|
|
void wait_eol();
|
2015-12-31 10:34:34 +01:00
|
|
|
void send_ok(const char* msg=nullptr);
|
2015-10-26 19:39:13 +01:00
|
|
|
|
|
|
|
NeoPixel leds;
|
|
|
|
Serial serial;
|
2015-10-25 22:06:31 +01:00
|
|
|
};
|
|
|
|
|
2015-12-31 10:34:34 +01:00
|
|
|
/// Initialise the hardware.
|
2015-10-26 19:39:13 +01:00
|
|
|
void Ser2Neo::init() {
|
2015-10-25 22:06:31 +01:00
|
|
|
leds.init();
|
|
|
|
serial.init();
|
|
|
|
}
|
|
|
|
|
2015-12-31 10:34:34 +01:00
|
|
|
/// Read a character, de-escaping if required.
|
2015-10-26 19:39:13 +01:00
|
|
|
int Ser2Neo::read_escaped() {
|
2015-10-25 22:06:31 +01:00
|
|
|
auto got = serial.getch();
|
|
|
|
if (got == EOF) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (got == ESC) {
|
|
|
|
got = serial.getch();
|
|
|
|
if (got == EOF) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
got ^= ESC;
|
|
|
|
}
|
|
|
|
return got;
|
|
|
|
}
|
|
|
|
|
2015-12-31 10:34:34 +01:00
|
|
|
/// Read the (potentially escaped) LED levels.
|
2015-10-26 19:39:13 +01:00
|
|
|
void Ser2Neo::read_leds() {
|
2015-10-25 22:06:31 +01:00
|
|
|
leds.clear();
|
2015-10-26 19:39:13 +01:00
|
|
|
while (true) {
|
2015-10-25 22:06:31 +01:00
|
|
|
int got = read_escaped();
|
|
|
|
if (got < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
leds.append(got);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-31 10:34:34 +01:00
|
|
|
/// Wait until the end-of-line character is received.
|
2015-10-26 19:39:13 +01:00
|
|
|
void Ser2Neo::wait_eol() {
|
2015-10-25 22:06:31 +01:00
|
|
|
while (serial.getch() != EOF) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-31 10:34:34 +01:00
|
|
|
/// Send OK with an optional message.
|
2015-10-26 19:39:13 +01:00
|
|
|
void Ser2Neo::send_ok(const char* msg) {
|
|
|
|
wait_eol();
|
|
|
|
serial.putstr("OK");
|
|
|
|
if (msg != nullptr) {
|
|
|
|
serial.putstr(" ");
|
|
|
|
serial.putstr(msg);
|
|
|
|
}
|
|
|
|
serial.putstr("\n");
|
|
|
|
}
|
|
|
|
|
2015-12-31 10:34:34 +01:00
|
|
|
/// Run the main loop. Process and run commands.
|
2015-10-26 19:39:13 +01:00
|
|
|
void Ser2Neo::run() {
|
2015-10-25 22:06:31 +01:00
|
|
|
sei();
|
|
|
|
|
2015-10-26 19:39:13 +01:00
|
|
|
serial.putstr("READY\n");
|
2015-10-25 22:06:31 +01:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
switch (serial.getch()) {
|
|
|
|
case '?':
|
2015-10-27 21:36:59 +01:00
|
|
|
send_ok("ser2neo 1 neopixel 16 grb");
|
2015-10-25 22:06:31 +01:00
|
|
|
break;
|
|
|
|
case '!':
|
2015-10-26 19:39:13 +01:00
|
|
|
send_ok("sync");
|
2015-10-25 22:06:31 +01:00
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
read_leds();
|
|
|
|
leds.write();
|
2015-10-26 19:39:13 +01:00
|
|
|
serial.putstr("OK\n");
|
2015-10-25 22:06:31 +01:00
|
|
|
break;
|
|
|
|
case EOF:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
wait_eol();
|
2015-10-26 19:39:13 +01:00
|
|
|
serial.putstr("ERROR\n");
|
2015-10-25 22:06:31 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-26 19:39:13 +01:00
|
|
|
static Ser2Neo ser2led;
|
|
|
|
|
2015-10-25 22:06:31 +01:00
|
|
|
int main() {
|
2015-10-26 19:39:13 +01:00
|
|
|
ser2led.init();
|
|
|
|
ser2led.run();
|
2015-10-25 22:06:31 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|