Subversion Repositories group.NITPanels

Rev

Rev 20 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

#include "usbdrv.h"
#include "config.h"

#ifndef NULL
#define NULL    ((void *)0)
#endif

#define USB_GET_STATE           100
#define USB_LEDS_SET            101
#define USB_GET_ANALOG          102
#define USB_SET_POWER_LED       103

/* ------------------------------------------------------------------------- */

uint8_t getKey(void);
inline void setLeds();

void analogInit();
uint8_t analogRead(uint8_t channel);

/*
volatile struct {
        uint8_t data;
        union {
                uint8_t led_method:1;
                uint8_t other:1;
                uint8_t reserved:6;
        };
} config;*/

static uchar usbReplyBuf[16];

volatile uint8_t pwrLed = 0;
volatile uint8_t currLeds = 0;
volatile uint8_t currKeys = 0;
volatile uint8_t analogPin = 0;
volatile uint8_t tmr0_ovf = 0;
volatile uint32_t systime = 0;

/* ------------------------------------------------------------------------- */

void hadUsbReset(void) {
}


uchar   usbFunctionSetup(uchar data[8])
{
    usbRequest_t    *rq = (void *)data;

        switch (rq->bRequest ) {
                case USB_GET_STATE:
                        usbReplyBuf[0] = currLeds;
                        usbReplyBuf[1] = currKeys;
                        usbMsgPtr = usbReplyBuf;
                        return sizeof(usbReplyBuf);
                case USB_LEDS_SET:
                        currLeds = rq->wValue.bytes[0];
                        return 0;
                case USB_GET_ANALOG:
                        usbReplyBuf[0] = (analogPin);
                        usbMsgPtr = usbReplyBuf;
                        return sizeof(usbReplyBuf);
                case USB_SET_POWER_LED:
                        pwrLed = rq->wValue.bytes[0];
        }

        return 0;
}

int main(void) {

        DIDR0 = 0x00;

  /*
  DDR : 1 = Output, 0 = Input
  PORT: 1 = Pullup for Input, otherwise set output
  PIN : Read input pin
  */

  /*
        PB0     - Output            - LED 3
        PB1     - Output            - LED 4
        PB2     - Output            - LED 5
        PB3     - Output            - LED 6
        PB4     - Output            - LED 7
        PB5     - Input                         - Config Switch 1
        PB6     - Osc
        PB7     - Osc
  */
  DDRB          = 0B00011111;
  PORTB         = 0B00000000;

  /*
        PC0     - Input, ADC            - Potentiometer
        PC1     - Output                        - Power LED
        PC2     - Input, Pullup         - ButtonPad 0
        PC3     - Input, Pullup         - ButtonPad 1
        PC4     - Input, Pullup         - ButtonPad 2
        PC5     - Input, Pullup         - ButtonPad 3
        PC6             - Reset
  */
  DDRC          = 0B00000010;
  PORTC         = 0B00111100;

  /*
        PD0     - Output                - ButtonPad Gnd0
        PD1     - Output                - ButtonPad Gnd1
        PD2     - USB D+
        PD3     - USB D-
        PD4     - Input                 - Config Switch 2
        PD5     - Output                - LED 0
        PD6     - Output                - LED 1
        PD7     - Output                - LED 2
  */
  DDRD          = 0B11100011;
  PORTD         = 0B00000011;

        // The USB connect stuff, flash the power led
        sbi(PORTC, PC1);
    usbDeviceDisconnect();
    _delay_ms(500);
    usbDeviceConnect();
    cbi(PORTC, PC1);

    // @TODO: Don't really need the system time anymore, remove?
    TIMSK0 = (1<<TOIE0);            // Enable timer overflow
    TCNT0 = 0x00;                   // Set Timer0 initial value to 0
    TCCR0B = (1<< CS00) ;           // /1 prescaler

    wdt_enable(WDTO_1S);                        // WatchDog at 1s
    usbInit();                                          // Init the USB port
    sei();                                                      // Enable interrupts

        setLeds();                                              // Set default LED status

        analogInit();                                   // Init the ADC for PC0 (ADC0)

        /*
         * @TODO: PowerSave - Only read ADC every 100ms
         * @TODO: PowerSave - Only set leds on change
         * @TODO: PowerSave - Sleep for a few us each cycle
         */
    for(;;){
        wdt_reset();
        usbPoll();                                      // Poll USB port (Every ~10ms!)
        currKeys = getKey();            // Check the button presses
        analogPin = analogRead(0);      // Read the pot (VolControl)
                setLeds();                                      // Set the leds
                                                                        // @TODO: Only do this on change
    }

    return 0;
}

inline void setLeds() {
        // Set the status leds.
        // @TODO: Verify that this doesn't mess with other port functions
        PORTB &= 0xE0;
        PORTB |= (0x1F & (currLeds >> 3));
        PORTD &= 0x1F;
        PORTD |= (0xE0 & (currLeds << 5));

        // Set the power led state
        if (pwrLed)
                sbi(PORTC, PC1);
        else
                cbi(PORTC, PC1);
}

// Gnd = PD0, PD1
// Btn = PC2, PC3, PC4, PC5
uint8_t getKey() {
        uint8_t key = 0;

        cbi(PORTD, PD1);                // Read the first row of buttons
        _delay_us(10);                  // Wait for the port change
        if (rbi(PINC, PC2) == 0) key = 1;
        if (rbi(PINC, PC3) == 0) key = 2;
        if (rbi(PINC, PC4) == 0) key = 4;
        if (rbi(PINC, PC5) == 0) key = 8;
        sbi(PORTD, PD1);

        cbi(PORTD, PD0);                // Read the second row of buttons
        _delay_us(10);
        if (rbi(PINC, PC2) == 0) key = 16;
        if (rbi(PINC, PC3) == 0) key = 32;
        if (rbi(PINC, PC4) == 0) key = 64;
        if (rbi(PINC, PC5) == 0) key = 128;
        sbi(PORTD, PD0);

        return key;
}

uint8_t analogRead(uint8_t channel) {
        ADMUX = (1<<ADLAR) | (1<<REFS0) | (0<<REFS1) | (channel & 0x0f);
        ADCSRA |= (1<<ADSC);                    // Start converting

        while (((ADCSRA >> ADSC) & 1)) {}   //Wait until conversion finished
        uint8_t result = ADCH;
        //ADCSRA |= (0<<ADSC);                  // Stop converting

        return result;
}

void analogInit() {
        ACSR |= (1<<ACD); // Disable analog comparator

        /*
        Setup ADC
        ADMUX: 8 bit mode, Avcc ref
        ADCSRA: Enable, 128 prescale
        */
        ADMUX = (1<<ADLAR) | (0<<REFS0) | (1<<REFS1);
        ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) ;
}

ISR(TIMER0_OVF_vect) {
        tmr0_ovf++;

        // Clk/1 TCCR0B = (1<< CS00);
        //20.0Mhz, 1ms = 78ovf
        //16.5Mhz, 1ms = 64ovf
        //12.0Mhz, 1ms = 46ovf

        if (tmr0_ovf>=78) {
                systime++;
                tmr0_ovf = 0;
        }
}