add fnordlicht VLC atmolight implementation

This commit is contained in:
King Kévin 2015-07-14 09:54:54 +02:00
parent 21944aabb5
commit fdf60c2eb4
3 changed files with 202 additions and 6 deletions

View File

@ -26,8 +26,19 @@
#include <avr/pgmspace.h> // Program Space Utilities
#include <avr/sleep.h> // Power Management and Sleep Modes
#include "uart.h" // basic UART functions
#include "main.h" // main definitions
#include "uart.h" // basic UART functions
#include "ws2812b.h" // to control WS2812B LEDs
/* global variables */
const uint8_t leds_per_channel[WS2812B_NB_CHANNELS] = {11,8,11,11,8,11}; // the led strips (top 1, top 2, left, bottom 1, bottom 2, right)
uint8_t nb_leds = 0; // the total number of LEDs (will be calculated on the number of LEDs per channel)
volatile uint8_t uart_in[16]; // input from USART, enough space for one fnordlight command or sync sequence
/* flags, set in the interrupts and handled in the main program */
volatile bool uart_flag = false; // data on UART has been received
volatile char uart_char = 0; // UART data
volatile bool command_flag = false; // a command has been received
/* switch off LED */
void led_off(void)
@ -57,6 +68,44 @@ void wdt_init(void)
return;
}
/* receive UART input */
ISR(USART_RX_vect) { /* UART receive interrupt */
uart_char = getchar(); // save current character
uart_flag = true; // warm main programm
}
/* process command */
void command_action(void)
{
/* parse command */
switch (uart_in[1]) {
case 0x01: // set LED colors
if (uart_in[0]<nb_leds) { // set LED color
for (uint8_t channel = 0; channel<sizeof(leds_per_channel); channel++) { // find right channel
if (uart_in[0]<leds_per_channel[channel]) { // find right LED
ws2812b_set_led_color(channel,uart_in[0],uart_in[4],uart_in[5],uart_in[6]);
break;
} else {
uart_in[0] -= leds_per_channel[channel]; // go to next channel
}
}
} else { // use additional LED setting as signal to show the LEDs
ws2812b_show();
}
break;
case 0x08: // stop color changing
ws2812b_show(); // use this as flush command
break;
case 0x80: // start bootloader
case 0x87: // start application
ws2812b_off();
ws2812b_show();
break;
default:
break; // all other commands are not relevant
}
}
/* initialize GPIO */
void io_init(void)
{
@ -69,18 +118,65 @@ void io_init(void)
/* LED */
LED_DDR |= (1<<LED_IO); // LED is driven by pin (set as output)
led_off();
sei(); /* enable interrupts */
/* WS2812B LEDs */
ws2812b_init();
ws2812b_off();
ws2812b_show();
}
int main(void)
{
uint8_t uart_in_i = 0; // UART input index
uint8_t escape_count = 0; // number of escape bytes received
io_init(); // initialize IOs
/* count the total number of LEDs */
for (uint8_t i=0; i<sizeof(leds_per_channel); i++) {
nb_leds += leds_per_channel[i];
}
led_on();
printf(PSTR("welcome on the VLC+fnordlicht+WS2812B AtmoLight\n"));
led_off();
while (true) { // endless loop for micro-controller
/* blinking LED example */
led_toggle();
_delay_ms(500);
while (uart_flag) {
/* go to next character but next got pass the last
* only sync sequences can be longer than 15, but should only be 16
* but sometimes (bug) they are longer
* then ignore the escape byte until the sequence ends
*/
uart_in[uart_in_i] = uart_char;
if (uart_in_i<sizeof(uart_in)-1) {
uart_in_i++;
}
if (uart_char==0x1b) { // escape byte received
if (escape_count<15) { // there should be maximum 15 escape bytes. ignore all additional
escape_count++; // count number of escape bytes
}
} else {
if (escape_count>=15) { // end of sync sequence
uart_in_i = 0; // reset input but don't handle sync sequence
}
escape_count = 0; // restart count
}
if (uart_in_i>=15 && escape_count<15) { // end of command
command_flag = true; // notify a command is ready
uart_in_i = 0; // reset input
}
uart_flag = false;
}
while (command_flag) { // UART input command is ready
led_on();
command_action(); // process command
command_flag = false; // clear flag
led_off();
}
}
return 0;
}

60
test.rb Executable file
View File

@ -0,0 +1,60 @@
#!/usr/bin/env ruby
# encoding: utf-8
# ruby: 1.9
require 'serialport'
atmolight = SerialPort.open("/dev/ttyUSB0",{ baud: 19200, databits: 8, parity: SerialPort::NONE, stop_bit: 1, flow_control: SerialPort::NONE})
# reset arduino
atmolight.dtr = 1
sleep 0.5
atmolight.dtr = 0
sleep 0.5
atmolight.flush_output
atmolight.flush_input
atmolight.baud = 19200
puts "waiting for welcome message"
puts atmolight.gets
puts "sending test commands"
commands = [
"\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # start bootloader
"\x00\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # start application
"\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x00", # sync sequence
"\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x00", # too long sync sequence
"\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # unhandled command
]
commands.each do |command|
sleep 0.5
atmolight.write command
atmolight.flush_output
end
# test all LEDs with red
puts "cycle LEDs"
60.times do |i|
atmolight.write [i,0x01,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00].pack("C*") # set LED to red
atmolight.flush_output
atmolight.write [0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00].pack("C*") # flush
atmolight.flush_output
sleep 0.25
atmolight.write [i,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00].pack("C*") # switch off LED
atmolight.flush_output
end
# increase white
puts "white fading"
atmolight.write "\x00\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
atmolight.flush_output
sleep 0.5
white = 0
while true do
start = Time.now
61.times do |i|
atmolight.write [i,0x01,0x00,0x00,white,white,white,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00].pack("C*") # set LED to red
atmolight.flush_output
end
white = (white+10)%256
puts "set white #{white} in #{Time.now-start} s"
end

40
vlc-fnordlicht-dump.txt Normal file
View File

@ -0,0 +1,40 @@
1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b00
ff0801000000000000000000000000
000180011e1e1e0000000000000000
010180011e1e1e0000000000000000
020180011e1e1e0000000000000000
030180011e1e1e0000000000000000
040180011e1e1e0000000000000000
050180011e1e1e0000000000000000
060180011e1e1e0000000000000000
070180011e1e1e0000000000000000
ff0801000000000000000000000000
1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b00
ff806b5627fc000000000000000000
1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b00
ff0801000000000000000000000000
000180018282820000000000000000
01018001817f7c0000000000000000
0201800183817e0000000000000000
030180018686860000000000000000
040180018c8c8c0000000000000000
050180018c8c8c0000000000000000
060180018a8a8a0000000000000000
07018001817f7c0000000000000000
000180018282820000000000000000
01018001817f7c0000000000000000
0201800183817e0000000000000000
030180018686860000000000000000
040180018c8c8c0000000000000000
050180018c8c8c0000000000000000
060180018a8a8a0000000000000000
07018001817f7c0000000000000000
ff0801000000000000000000000000
1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b00
ff806b5627fc000000000000000000
1b1b1b1b1b1b1b1b1b
1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b00
ff0801000000000000000000000000