412 lines
7.8 KiB
C
412 lines
7.8 KiB
C
/*
|
|
* ----------------------------------------------------------------------------
|
|
* "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
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
|
|
|
|
#include "rgbyteclock.h"
|
|
#include "timer.h"
|
|
#include "ledcontroller.h"
|
|
#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_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;
|
|
uint16_t r,g,b; // colors
|
|
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:
|
|
// TODO: animation that shows sequence color after color
|
|
for( int i=0; i<sequence_index; i++ ) {
|
|
get_color( &r, &g, &b, sequence[i] );
|
|
led_set( i, r, g, b );
|
|
}
|
|
|
|
// display last color for 2 seconds
|
|
if( now - t1 > 2000 || (get_button())) {
|
|
// hide sequence
|
|
for( int i=0; i<12; i++ ) {
|
|
get_color( &r, &g, &b, COLOR_BLACK );
|
|
led_set( i, r, g, b);
|
|
}
|
|
|
|
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_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;
|
|
|
|
index = (t_diff%1200)/100;
|
|
if( !(t_diff % 100) ) {
|
|
// every 100ms
|
|
get_color( &r, &g, &b, (random()%6)+1 );
|
|
led_set( index, r, g, b );
|
|
}
|
|
|
|
// next LED in line is dark to mark the update spot better
|
|
index++;
|
|
led_set( index%12, 0,0,0 );
|
|
|
|
if( now - animation_start > 2400 ) {
|
|
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 ) {
|
|
for( int i=0; i<12; i++ ) {
|
|
led_set( i, 0x00, 0x00, 0x00);
|
|
}
|
|
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 ) {
|
|
for( int i=0; i<12; i++ ) {
|
|
led_set( i, 0x00, 0x00, 0x00);
|
|
}
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
}
|
|
|
|
if( t_diff > 2000 ) {
|
|
for( int i=0; i<12; i++ ) {
|
|
led_set( i, 0x00, 0x00, 0x00);
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|