ser2neo/ser2neo.cc

134 lines
2.8 KiB
C++
Raw Permalink Normal View History

// 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.
///
class Ser2Neo {
public:
void init();
void run();
2015-10-25 22:06:31 +01:00
private:
static const uint8_t EOF = '\r';
static const uint8_t ESC = '+';
2015-10-25 22:06:31 +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);
NeoPixel leds;
Serial serial;
2015-10-25 22:06:31 +01:00
};
2015-12-31 10:34:34 +01:00
/// Initialise the hardware.
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.
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.
void Ser2Neo::read_leds() {
2015-10-25 22:06:31 +01:00
leds.clear();
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.
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.
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.
void Ser2Neo::run() {
2015-10-25 22:06:31 +01:00
sei();
serial.putstr("READY\n");
2015-10-25 22:06:31 +01:00
for (;;) {
switch (serial.getch()) {
case '?':
send_ok("ser2neo 1 neopixel 16 grb");
2015-10-25 22:06:31 +01:00
break;
case '!':
send_ok("sync");
2015-10-25 22:06:31 +01:00
break;
case 'l':
read_leds();
leds.write();
serial.putstr("OK\n");
2015-10-25 22:06:31 +01:00
break;
case EOF:
break;
default:
wait_eol();
serial.putstr("ERROR\n");
2015-10-25 22:06:31 +01:00
break;
}
}
}
static Ser2Neo ser2led;
2015-10-25 22:06:31 +01:00
int main() {
ser2led.init();
ser2led.run();
2015-10-25 22:06:31 +01:00
return 0;
}