rgbyteclock-code/rgbyteclock.c

471 lines
8.8 KiB
C
Raw Normal View History

2014-03-01 03:54:52 +01:00
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <struppi@struppi.name> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return.
* (c) 2014 Stefan Rupp
* ----------------------------------------------------------------------------
*/
2014-03-01 03:50:09 +01:00
#include "rgbyteclock.h"
2014-03-03 05:01:36 +01:00
#include "timer.h"
#include "ledcontroller.h"
2014-03-15 05:47:41 +01:00
#include "util.h"
#define SEED_RNG 0
#define INIT 1
#define INTRO 2
#define INTRODUCE_COLORS 3
#define SHOW_SEQUENCE 4
#define GET_USER_SEQUENCE 5
#define USER_GUESS_OK 6
#define USER_GUESS_NOK 7
#define EXTEND_SEQUENCE 8
#define WIN 9
int8_t show_anim_sequence( uint32_t now, uint32_t animation_start );
2014-03-15 05:47:41 +01:00
int8_t show_intro( uint32_t now, uint32_t animation_start );
int8_t show_introduce_colors( uint32_t now, uint32_t animation_start );
void show_anim_wait_seed( uint32_t now, uint32_t animation_start );
int8_t show_anim_ok( uint32_t now, uint32_t animation_start );
int8_t show_anim_nok( uint32_t now, uint32_t animation_start );
int8_t get_sequence( uint32_t now, uint32_t animation_start );
int8_t show_anim_win( uint32_t now, uint32_t animation_start );
static uint8_t sequence[12];
static uint8_t sequence_index;
static uint8_t input_sequence_index;
static uint8_t colorScheme[2];
void rgbyteclock(void) {
uint32_t now, t1;
int8_t end;
uint8_t button = BUTTON_NONE;
uint8_t gameState = SEED_RNG;
ledcontroller_turn_all_on();
DDRC &= ~(1<<PC5); // use pullup
while ( 1 ) {
now = timer_get( );
switch( gameState ) {
case SEED_RNG:
// get seed for RNG from button press
show_anim_wait_seed( now, t1 );
button = get_button( );
if( button != BUTTON_NONE ) {
init_random( (uint16_t)(now - t1));
gameState = INIT;
t1 = now;
}
break;
case INIT:
PORTC &= ~(1<<PC5);
sequence_index = 0;
input_sequence_index = 0;
gameState = INTRO;
colorScheme[0] = (random()%6) +1;
colorScheme[1] = colorScheme[0];
while( colorScheme[0] == colorScheme[1] ) {
colorScheme[1] = (random()%6) +1;
}
// all buttons dark
for( int i=12; i<14; i++ ) {
led_set( i, 0,0,0 );
}
t1 = now;
break;
case INTRO:
// show a nice animation to indicate the start of the game
end = show_intro( now, t1 );
if( end ) {
gameState = INTRODUCE_COLORS;
t1 = now;
}
break;
case INTRODUCE_COLORS:
end = show_introduce_colors( now, t1 );
if( end ) {
gameState = EXTEND_SEQUENCE;
t1 = now;
}
break;
case SHOW_SEQUENCE:
end = show_anim_sequence( now, t1 );
2014-03-15 05:47:41 +01:00
if( end == 1 ) {
2014-03-15 05:47:41 +01:00
gameState = GET_USER_SEQUENCE;
t1 = now;
}
break;
case GET_USER_SEQUENCE:
end = get_sequence( now, t1 );
if( end == 1 ) {
gameState = USER_GUESS_NOK;
t1 = now;
}
if( end == 2 ) {
gameState = USER_GUESS_OK;
t1 = now;
}
break;
case USER_GUESS_OK:
end = show_anim_ok( now, t1 );
if( end ) {
gameState = EXTEND_SEQUENCE;
t1 = now;
}
break;
case USER_GUESS_NOK:
end = show_anim_nok( now, t1 );
if( end ) {
gameState = INIT;
t1 = now;
}
break;
case EXTEND_SEQUENCE:
if(sequence_index >= 12) {
gameState = WIN;
continue;
}
else {
gameState = SHOW_SEQUENCE;
}
if( random()&1 ) {
sequence[sequence_index] = colorScheme[0];
}
else {
sequence[sequence_index] = colorScheme[1];
}
sequence_index++;
break;
case WIN:
end = show_anim_win( now, t1 );
if( end ) {
gameState = INIT;
t1 = now;
}
break;
}
led_flush( );
}
}
int8_t get_sequence( uint32_t now, uint32_t animation_start ) {
uint16_t r,g,b;
uint8_t button;
uint8_t color;
uint8_t guessOK;
button = get_button( );
color = sequence[input_sequence_index];
guessOK = 0;
if( button == BUTTON_RO ) {
if( color == colorScheme[0] ) {
guessOK = 1;
}
}
else if( button == BUTTON_LO ) {
if( color == colorScheme[1] ) {
guessOK = 1;
}
}
else {
return 0;
}
if( guessOK ) {
// draw what user entered until now
get_color( &r, &g, &b, color );
led_set( input_sequence_index, r, g, b );
input_sequence_index++;
if( input_sequence_index >= sequence_index) {
input_sequence_index = 0;
return 2; // entire sequence right
}
return 0; // right but not finished
}
return 1; // user guessed wrong
}
/*
##############
# ANIMATIONS #
##############
*/
int8_t show_anim_sequence( uint32_t now, uint32_t animation_start ) {
uint32_t t_diff = now - animation_start;
uint16_t r,g,b;
uint8_t tmp_index;
const uint16_t holdTime=1000 /*ms*/, stepSpeed=500 /*ms*/;
tmp_index = (t_diff/stepSpeed) +1;
if( tmp_index > sequence_index ) {
tmp_index = sequence_index;
}
for( int i=0; i<tmp_index; i++ ) {
get_color( &r, &g, &b, sequence[i] );
led_set( i, r, g, b );
}
// display last color for 2 seconds
if( t_diff > (sequence_index * stepSpeed)+holdTime ) {
// hide sequence
for( int i=0; i<12; i++ ) {
get_color( &r, &g, &b, COLOR_BLACK );
led_set( i, r, g, b);
}
return 1;
}
return 0;
}
2014-03-15 05:47:41 +01:00
int8_t show_introduce_colors( uint32_t now, uint32_t animation_start ) {
uint32_t t_diff = now - animation_start;
uint16_t r,g,b;
// all ring LEDs off
for( int i=0; i<12; i++ ) {
led_set( i, 0,0,0 );
}
if( t_diff%100 < 50 ) {
// put gamecolors on the buttons
get_color( &r, &g, &b, colorScheme[0] );
led_set( 12, r, g, b); // RO
get_color( &r, &g, &b, colorScheme[1] );
led_set( 13, r, g, b); // LO
}
else {
for( int i=12; i<14; i++ ) {
get_color( &r, &g, &b, COLOR_BLACK );
led_set( i, r,g,b );
}
}
if( t_diff > 1000 ) {
return 1;
}
return 0;
}
void show_anim_wait_seed( uint32_t now, uint32_t animation_start ) {
uint32_t t_diff = (now - animation_start)%1000;
uint16_t w;
if( t_diff < 500 ) {
// fade up
w = (MAX_BRIGHTNESS/500) * t_diff;
for( int i=0; i<12; i++ ) {
led_set( i, w, w, w);
}
}
else {
// fade down
w = MAX_BRIGHTNESS - (MAX_BRIGHTNESS/500) * (t_diff-500);
for( int i=0; i<12; i++ ) {
led_set( i, w, w, w);
}
}
}
int8_t show_intro( uint32_t now, uint32_t animation_start ) {
// Animation: rotate a single LED once across the circle
uint32_t t_diff = now - animation_start;
uint16_t r,g,b;
uint8_t index;
static uint8_t tmp_sequence[12], tmp;
static uint8_t step = 0;
if( step == 0) {
for( int i=0; i<12; i++) {
tmp_sequence[i] = (random()%6)+1;
}
step = 1;
}
2014-03-15 05:47:41 +01:00
index = (t_diff%1200)/100;
// print a chain of random colors
if( !(t_diff % 100) && (step == 1) ) {
PORTC ^=(1<<PC5);
2014-03-15 05:47:41 +01:00
// every 100ms
get_color( &r, &g, &b, tmp_sequence[index] );
2014-03-15 05:47:41 +01:00
led_set( index, r, g, b );
// goto next animation sequence
if( t_diff > 1200 ) {
step = 2;
}
2014-03-15 05:47:41 +01:00
}
// rotate chain 180 degrees
if( !(t_diff % 100) && (step == 2) ) {
// barrelshift every 100ms
tmp = tmp_sequence[11];
for( int i=10; i>=0; i-- ) {
tmp_sequence[i+1] = tmp_sequence[i];
}
tmp_sequence[0] = tmp;
// update all at once
for(int i=0; i<12; i++ ) {
get_color( &r, &g, &b, tmp_sequence[i] );
led_set( i, r, g, b );
}
}
//led_set( index, r, g, b );
if( (now - animation_start) > 2400 ) {
step = 0;
2014-03-15 05:47:41 +01:00
return 1;
}
return 0;
}
int8_t show_anim_ok( uint32_t now, uint32_t animation_start ) {
uint32_t t_diff = now - animation_start;
uint16_t g;
if( t_diff < 500 ) {
g = (MAX_BRIGHTNESS/500) * t_diff;
for( int i=0; i<12; i++ ) {
led_set( i, 0x00, g, 0x00);
}
}
else {
g = MAX_BRIGHTNESS - (MAX_BRIGHTNESS/500) * (t_diff-500);
for( int i=0; i<12; i++ ) {
led_set( i, 0x00, g, 0x00);
}
}
if( t_diff > 1000 ) {
2014-03-16 01:01:06 +01:00
for( int i=0; i<12; i++ ) {
led_set( i, 0x00, 0x00, 0x00);
}
2014-03-15 05:47:41 +01:00
return 1;
}
return 0;
}
int8_t show_anim_nok( uint32_t now, uint32_t animation_start ) {
uint32_t t_diff = now - animation_start;
uint16_t r,g,b;
if( t_diff%100 < 50 ) {
for( int i=0; i<12; i++ ) {
get_color( &r, &g, &b, COLOR_RED );
led_set( i, r,g,b );
}
}
else {
for( int i=0; i<12; i++ ) {
get_color( &r, &g, &b, COLOR_BLACK );
led_set( i, r,g,b );
}
}
if( t_diff > 1000 ) {
2014-03-16 01:01:06 +01:00
for( int i=0; i<12; i++ ) {
led_set( i, 0x00, 0x00, 0x00);
}
2014-03-15 05:47:41 +01:00
return 1;
}
return 0;
}
int8_t show_anim_win( uint32_t now, uint32_t animation_start ) {
uint32_t t_diff = now - animation_start;
uint16_t b;
2014-03-01 03:50:09 +01:00
2014-03-15 05:47:41 +01:00
if( t_diff < 1000 ) {
b = (MAX_BRIGHTNESS/1000) * t_diff;
for( int i=0; i<12; i++ ) {
led_set( i, 0x00, 0x00, b);
}
}
else {
b = MAX_BRIGHTNESS - (MAX_BRIGHTNESS/1000) * (t_diff-1000);
for( int i=0; i<12; i++ ) {
led_set( i, 0x00, 0x00, b);
}
2014-03-01 03:50:09 +01:00
2014-03-15 05:47:41 +01:00
}
2014-03-01 03:50:09 +01:00
2014-03-15 05:47:41 +01:00
if( t_diff > 2000 ) {
2014-03-16 01:01:06 +01:00
for( int i=0; i<12; i++ ) {
led_set( i, 0x00, 0x00, 0x00);
}
2014-03-15 05:47:41 +01:00
return 1;
}
return 0;
2014-03-01 03:50:09 +01:00
}