Rev 77 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/* Name: main.c
* Project: EasyLogger
* Author: Christian Starkjohann
* Creation Date: 2006-04-23
* Tabsize: 4
* Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
* License: Proprietary, free under certain conditions. See Documentation.
* This Revision: $Id$
*/
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "usbdrv.h"
#include "oddebug.h"
#include "config.h"
#ifndef NULL
#define NULL ((void *)0)
#endif
/* ------------------------------------------------------------------------- */
struct {
union {
int16_t axis[3];
struct {
int16_t axis0:16;
int16_t axis1:16;
int16_t axis2:16;
};
uint8_t buttons;
struct {
int8_t b1:1;
int8_t b2:2;
int8_t reserved:6;
};
};
} reportBuffer;
volatile struct {
uint8_t current;
uint8_t last;
uint8_t mask;
} pcInt[1];
volatile struct {
uint8_t button;
uint8_t timer;
} buttons;
static uchar idleRate; /* in 4 ms units */
volatile uint8_t tmr0_ovf = 0;
volatile uint32_t systime = 0;
/* ------------------------------------------------------------------------- */
const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x38, // USAGE (Y)
0x16, 0x00, 0x80, // Log Min -32768
0x26, 0xff, 0x7f, // Log max 32768
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x03, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x02, // USAGE_MAXIMUM (Button 2)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data;
//usbMsgPtr = reportBuffer;
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){
if(rq->bRequest == USBRQ_HID_GET_REPORT){
return sizeof(reportBuffer);
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){
usbMsgPtr = &idleRate;
return 1;
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){
idleRate = rq->wValue.bytes[1];
}
}else{
}
return 0;
}
static void calibrateOscillator(void) {
uchar step = 128;
uchar trialValue = 0, optimumValue;
int x, optimumDev;
int targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);
/* do a binary search: */
do {
OSCCAL = trialValue + step;
x = usbMeasureFrameLength(); /* proportional to current real frequency */
if(x < targetValue) /* frequency still too low */
trialValue += step;
step >>= 1;
} while(step > 0);
/* We have a precision of +/- 1 for optimum OSCCAL here */
/* now do a neighborhood search for optimum value */
optimumValue = trialValue;
optimumDev = x; /* this is certainly far away from optimum */
for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
x = usbMeasureFrameLength() - targetValue;
if(x < 0)
x = -x;
if(x < optimumDev){
optimumDev = x;
optimumValue = OSCCAL;
}
}
OSCCAL = optimumValue;
}
void usbEventResetReady(void) {
cli();
calibrateOscillator();
sei();
eeprom_write_byte(0, OSCCAL); /* store the calibrated value in EEPROM */
}
void usbSendHidReport(uchar * data, uchar len) {
usbSetInterrupt(data, len);
}
int main(void) {
uchar i;
uchar calibrationValue;
calibrationValue = eeprom_read_byte(0); /* calibration value from last time */
if(calibrationValue != 0xff){
OSCCAL = calibrationValue;
}
odDebugInit();
usbDeviceDisconnect();
for(i=0;i<20;i++){ /* 300 ms disconnect */
_delay_ms(15);
}
usbDeviceConnect();
wdt_enable(WDTO_1S);
PCMSK |= (( 1 << PCINT3 ) | ( 1 << PCINT4 )); //enable encoder pins interrupt sources
GIMSK |= ( 1 << PCIE ); //enable pin change interupts
TIMSK = (1<<TOIE0); // Enable timer overflow
TCNT0 = 0x00; // Set Timer0 initial value to 0
TCCR0B = (1<< CS01) ; // /1 prescaler
DDRB = 0B00000001;
PORTB = 0B00000000;
usbInit();
sei();
reportBuffer.axis0 = 0;
reportBuffer.axis1 = 0;
reportBuffer.axis2 = 0;
reportBuffer.buttons = 0;
for(;;){ /* main event loop */
wdt_reset();
usbPoll();
if(usbInterruptIsReady()){
// Check if our buttons need pressing
reportBuffer.buttons = 0;
if (buttons.timer != 0) {
if (buttons.button == 1)
reportBuffer.b1 = 1;
else
reportBuffer.b2 = 1;
}
usbSendHidReport(&reportBuffer, sizeof(reportBuffer));
}
}
return 0;
}
void pcInterrupt(uint8_t pcint) {
switch (pcint) {
case 0: pcInt[pcint].current = PINB; break;
}
pcInt[pcint].mask = pcInt[pcint].current ^ pcInt[pcint].last;
pcInt[pcint].last = pcInt[pcint].current;
if (pcInt[pcint].mask == 0)
return;
// Check which pin caused the interrupt. If they both
// equal 0, the pin that interrupted is the direction
if (rbi(pcInt[pcint].current, PCINT3) == 0
&& rbi(pcInt[pcint].current, PCINT4) == 0
&& rbi(pcInt[pcint].mask, PCINT4) ) {
if (reportBuffer.axis2 < 32500)
reportBuffer.axis2 += 200;
buttons.button = 1;
buttons.timer = 5;
} else if (rbi(pcInt[pcint].current, PCINT3) == 0
&& rbi(pcInt[pcint].current, PCINT4) == 0
&& rbi(pcInt[pcint].mask, PCINT3) ) {
if (reportBuffer.axis2 > -32500)
reportBuffer.axis2 -= 200;
buttons.button = 2;
buttons.timer = 5;
}
// Clear the mask so we know we've delth with it
pcInt[pcint].mask = 0;
}
ISR(PCINT0_vect) {
pcInterrupt(0);
}
ISR(TIMER0_OVF_vect) {
tmr0_ovf++;
if (tmr0_ovf>=50) {
systime++;
tmr0_ovf = 0;
if (buttons.timer != 0)
buttons.timer--;
}
}