src/hello.c
author Tero Marttila <terom@paivola.fi>
Fri, 04 Apr 2014 01:04:41 +0300
changeset 56 3b837eaf1b6d
parent 55 04c625712e35
child 57 ee412c5be8b1
permissions -rw-r--r--
hello: expand to two led7seg displays
#include <avr/io.h>

#include "stdlib.h"
#include "timer.c" // XXX
#include "serial.c" // XXX
#include "spi.c" // XXX

static enum state {
    START       = '\n',
    CMD_SET     = 's',
    ARG_CHAR    = '0',
    ERROR       = '!',
} state = START, cmd = 0;

static enum {
    CMD_LED_1   = 0,
} cmd_led = 0;

static char arg_char;

static unsigned char led_state = 0;

int command (enum state cmd)
{
    switch (cmd) {
        case CMD_SET:
            led_state = arg_char;

            return 0;

        default:
            return 1;
    }
}

char input (char c)
{
    if (c == '\r') {
        char ret = '?';

        // command state
        switch (state) {
            case START:
                cmd = 0;
                break;

            case CMD_SET:
                break;

            case ARG_CHAR:
                break;

            case ERROR:
                cmd = 0;
                break;
        }

        // command
        if (!cmd) {
            ret = ' ';
        } else if (command(cmd)) {
            ret = '!';
        } else {
            ret = '\n';
        }
        
        // return to START with response
        state = START;
        return ret;

    } else if (31 < c && c < 128) {
        // process input char
        switch (state) {
            case START:
                if (c == 's') {
                    cmd = CMD_SET;
                    state = ARG_CHAR;
                    arg_char = 0;
                    return state;

                } else if (c == 'S') {
                    cmd = state = CMD_SET;
                    arg_char = 255;
                    return state;
                }
            break;

            /* 
            case CMD_SET:
                if (c == '1') {
                    cmd_led = CMD_LED_1;
                    state = ARG_CHAR;
                    arg_char = 0;
                } else {
                    state = ERROR;
                }

                break;
            */
            case ARG_CHAR:
                if (c >= '0' && c <= '9') {
                    arg_char *= 10;
                    arg_char += (c - '0');

                    return c;
                }
            break;
        }

        // reject
        state = ERROR;
        return ERROR;

    } else {
        // ignore
        return ' ';
    }
}

#define LED7_DDR    DDRB
#define LED7_PORT   PORTB
#define LED7_OE     PORTB1

// common anode?
#define LED7_ANODE  0

#define LED7_OFFSET 0
#define LED7_COUNT  2

static const uint8_t LED7SEG_FONT[] = {
    0b00111111,	// 0
    0b00000110,	// 1
    0b01011011,	// 2
    0b01001111,	// 3
    0b01100110,	// 4
    0b01101101,	// 5
    0b01111101,	// 6
    0b00000111,	// 7
    0b01111111,	// 8
    0b01100111,	// 9
    0b01110111,	// A
    0b01111100,	// B
    0b00111001,	// C
    0b01011110,	// D
    0b01111001,	// E
    0b01110001,	// F
};

enum {
    LED7SEG_DOT     = 0b10000000,
};

void led7_init (void)
{
    sbi(&LED7_PORT, LED7_OE); // disabled (low)
    sbi(&LED7_DDR, LED7_OE); // out
}

/*
 * Update external IO.
 */
void led7_update_raw (uint8_t *led7, char count)
{
    int i;

    for (i = 0; i < count; i++) {
        char raw = LED7SEG_FONT[led7[i]];

        spi_tx[LED7_OFFSET + i] = LED7_ANODE ? ~raw  : raw;
    } 
}

void led7_update_hex (unsigned char c)
{
    uint8_t led7[2];

    led7[0] = c >> 4;
    led7[1] = c & 0xF;
    
    return led7_update_raw(led7, sizeof(led7));
}

void led7_update ()
{
    static unsigned char i = 0;
    
    if (i) {
        // enable display
        cbi(&LED7_PORT, LED7_OE);
    }
    
    led7_update_hex(led_state);
 
    i++;
}

#define DEBUG_DDR   DDRB
#define DEBUG_PORT  PORTB
#define DEBUG_LED   0

int main (void)
{
    led7_init();
    timer_init();
    serial_init();
    spi_init();

    // led_init();
    sbi(&DEBUG_DDR, DEBUG_LED);

    sei();

    // start
    char c;
    unsigned short timeout = 0;
        
    serial_write(state);

    while (true) {
        // TODO: SPI timer
        led7_update();
        spi_update();

        // toggle
        if (led_state == 0) {
            timeout = 0;
            cbi(&DEBUG_PORT, DEBUG_LED);

        } else if (led_state == 255) {
            timeout = 0;
            sbi(&DEBUG_PORT, DEBUG_LED);

        } else {
            // as Hz
            timeout = (16000 / led_state);
            xbi(&DEBUG_PORT, DEBUG_LED);
        }
        
        // sleep
        if (timer_sleep(timeout)) {
            c = '.';

        } else if ((c = serial_read())) {
            // got serial data
            c = input(c);

        } else {
            c = '?';
        }
        
        // output...
        serial_write(c);
    }
}