/************************************************************
* Spell text on LEDs - POV (Persistence of Vision)          *  
*                                                           *  
* 20050920                                                  *  
* sklarm@electric-clothing.com                              *  
* m@unlikely.org                                            *  
*                                                           *  
************************************************************/
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

#define TEXT_MAXLEN 9           /* MAX length of characters to display */

#define TIMER0_PRESCALER_1 0x01
#define TIMER0_PRESCALER_8 0x02
#define TIMER0_PRESCALER_64 0x03
#define TIMER0_PRESCALER_256 0x04
#define TIMER0_PRESCALER_1024 0x05

void letter_to_pov(char alpha);
SIGNAL(SIG_OVERFLOW0);

/* 
 *  Blink this string 
 *  - user lowercase only
 */
char message[TEXT_MAXLEN] = "code:";

/*
 * Letter of message
 */
char *lom;

/*
 * Column of Letter
 */
int *col;

/*
 * White Space flag (auto inserted between characters)
 */
int ws=0;

int main(void)
{

        /* 
         * Enable PORTA 0-6 as outputs
         * Enable PORTB 0-6 as outputs
         */
        DDRA=0x7F;
        DDRB=0x7F;

        /* 
         * prescaler setup for timer0
         */
        TCCR0=TIMER0_PRESCALER_256;

        /* 
         * start timer with nothing
         */
        TCNT0=0x00;

        /*
         * set lowest BIT of TIMSK to enable overflow interrupt
         */
        timer_enable_int(1<<TOIE0);

        /*
         * Set (global) Enable Interrupts
         */
        sei();

        lom = message;
        letter_to_pov(*lom);

        while(1);

}


/* 
 * Timer0 Interrupt Service Routine
 * - 8bit
 * - rollover occurs at 255
 * - TCCR0 - Timer Counter Control Register
 * - 256 divide ( CS00 = 0 / CS01 = 0 / CS02 = 1 )
 * - 1MHz (clock) / 256 prescalar = 3906.25
 * - 1 / 3906.25 (period) = .256ms = 256us
 * - requires reload of (256 - 234) 
 * - reload 22
 * - 22us
 * - frequency 5405Hz
 * - Flash letters at 5405Hz
 */
SIGNAL(SIG_OVERFLOW0) {

        /* 
         * reload timer 
         * prescalar 256 
         */
        TCNT0=0xEA;

        /*
         * Logic for adding a double white space delay 
         * between each characters hex codes.
         *
         * Move to next letter when we have reached the end 
         * hex code. 
         */
        if ( *col == 0x00  && ws < 2 ) {
                ws = ws + 1;
        } else if ( ws >= 2 ) {
                lom++;
                letter_to_pov(*lom);
                ws = 0;
        }

        /* 
         * restart message 
         */
        if ( *lom == ':' ) {
                lom = message;
                letter_to_pov(*lom);
        }

        /*
         * Send Column of letters to PORTB
         */
        PORTB = *col;
        PORTA = *col;
        col++;

}


/* 
 *  Alphabetic representation in 7bit coordinates 
 *  Converts letter to blinking light format 
 *
 *  (example 'a' , 'b', 'c', and 'd' below)
 * 
 *    *****   ******   ******  *******
 *   *     *  *    *  *        *      *
 *   *     *  *   *  *         *      *
 *   *******  ****   *         *      *
 *   *     *  *   *  *         *      *
 *   *     *  *    *  *        *      *
 *   *     *  ******   ******  *******
 * 
 */
void letter_to_pov(char alpha)
{
    static int space[] = {0x00};
    static int letters[][20] = {
        {0x3f,0x48,0x48,0x48,0x3f,0x00},           /* A */
        {0x7f,0x49,0x49,0x49,0x36,0x00},           /* B */
        {0x3e,0x41,0x41,0x41,0x22,0x00},           /* C */
        {0x7f,0x41,0x41,0x41,0x3e,0x00},           /* D */
        {0x7f,0x49,0x49,0x41,0x00},                /* E */
        {0x7f,0x48,0x48,0x40,0x00},                /* F */
        {0x3e,0x41,0x49,0x49,0x2e,0x00},           /* G */
        {0x7f,0x08,0x08,0x08,0x7f,0x00},           /* H */
        {0x7f,0x00},                               /* I */
        {0x02,0x01,0x01,0x7e,0x00},                /* J */
        {0x7f,0x08,0x18,0x24,0x43,0x00},           /* K */
        {0x7f,0x01,0x01,0x01,0x00},                /* L */
        {0x3f,0x40,0x40,0x3f,0x40,0x40,0x3f,0x00}, /* M */
        {0x7f,0x20,0x1C,0x02,0x7f,0x00},           /* N */
        {0x3e,0x41,0x41,0x41,0x3e,0x00},           /* O */
        {0x3f,0x48,0x48,0x48,0x30,0x00},           /* P */
        {0x3e,0x41,0x45,0x43,0x3f,0x00},           /* Q */
        {0x7f,0x48,0x4c,0x4A,0x31,0x00},           /* R */
        {0x32,0x49,0x49,0x49,0x26,0x00},           /* S */
        {0x40,0x40,0x7F,0x40,0x40,0x00},           /* T */
        {0x3e,0x01,0x01,0x01,0x3e,0x00},           /* U */
        {0x78,0x06,0x01,0x06,0x78,0x00},           /* V */
        {0x7e,0x01,0x01,0x7e,0x01,0x01,0x7e,0x00}, /* W */
        {0x41,0x22,0x1c,0x22,0x41,0x00},           /* X */
        {0x40,0x20,0x1f,0x20,0x40,0x00},           /* Y */
        {0x43,0x45,0x49,0x51,0x61,0x00}            /* Z */
    };

        if (alpha == ' ') {
                col = space;
        } else {
                col = letters[alpha - 'a'];
        }
}