/* Programm für VR-FlyStick (Variante B: USB-HID-Joystick)
* Hardware:
* Das Gerät benutzt 2 Knöpfe und 2 LEDs.
* grün = OK, rot = Tastendruck
*
* tabsize = 8, encoding = utf-8?, lineends = LF
*/
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include "usbdrv.h"
/************
* Hardware *
************/
/*
Verwendung der Ports:
PA0 (13) - Taster T1 (oben)
PA1 (12) - Taster T2 (unten)
PA2 (11) - LED grün
PA3 (10) - LED rot
PA4 (9) SCK Programmieranschluss
PA5 (8) MISO Programmieranschluss
PA6 (7) MOSI Programmieranschluss
PA7 (6) - -
PB0 (2) - -
PB1 (3) - USB D+
PB2 (5) - USB D-
PB3 (4) /RESET Programmieranschluss
Verwendung der Zähler:
Timer0 (8 bit) = für OSCCAL-Synchronisation an USB
*/
static struct {
uchar keystate; // Tastenstatus
}InputReport;
/*******
* LED *
*******/
static uchar Led_T; // flashing time in ms, 0 = LED is steady
static uchar Led_F; // flashing frequency in ms (half period)
static uchar Led_C; // flash-counter (via SOF pulses)
// LED-Blinken (ausgelöst von SETUP-Transfers) ist hier nur Schnicknack
void Led_Start(uchar t) {
if (!Led_T) {
Led_C=t;
PORTA&=~0x0C; // LED ausschalten
}
Led_T=Led_F=t;
}
static void Led_On1ms(void) {
uchar led_t=Led_T, led_c; // lokal vorhalten
uchar mask;
if (!led_t) return;
led_c=Led_C;
mask = InputReport.keystate ? 0x08 : 0x04; // rot oder grün
if (!--led_c) {
PORTA^=mask; // LED ein- oder ausschalten
led_c=Led_F;
}
if (!--led_t) PORTA|=mask; // LED einschalten
Led_T=led_t;
Led_C=led_c;
}
/*******
* USB *
*******/
// USB Report-Deskriptor
PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
0x05, 0x01, // G Usage Page (Generic Desktop)
0x09, 0x04, // L Usage (Joystick)
0xA1, 1, // M Collection (Application)
0x15, 0, // G Logical Minimum (0)
0x25, 1, // G Logical Maximum (1)
0x75, 1, // G Report Size (1 bit)
0x95, 2, // G Report Count (2)
0x05, 0x09, // G Usage Page (Buttons)
0x19, 0x01, // L Usage Minimum (Button 1)
0x29, 0x02, // L Usage Maximum (Button 2)
0x81, 0x02, // M Input (Var)
0x95, 6, // G Report Count (6)
0x81, 0x01, // M Input (Const)
0xC0}; // M End Collection
/***********************
* SETUP data received *
***********************/
uchar usbFunctionSetup(uchar data[8]) {
usbRequest_t *rq = (void*)data;
/* class request type (x01x xxxx) */
if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
if (rq->bRequest == USBRQ_HID_GET_REPORT) { // wValueH: ReportType, wValueL: ReportID
if (rq->wValue.bytes[1] == 1) { // Input
usbMsgPtr = (uchar*)&InputReport;
return sizeof(InputReport);
}
}
}
return 0;
}
/*************************************
* Initialisierung und Hauptschleife *
*************************************/
int __attribute__((noreturn)) main(void) {
uchar SofCmp=0;
uchar keychange=0;
uchar mcusr = MCUSR;
MCUSR = 0;
OSCCAL= 0xCF;
ACSR = 0x80; // Analogvergleicher abschalten: –70µA
WDTCSR = 0x18; // Watchdog überlebt RESET: abschalten!
WDTCSR = 0;
if (mcusr & (1 << WDRF)) {
if (USBIN & USBMASK) { // no SE0 state?
GIMSK = 0x40;
MCUCR = 0x30; // SLEEP_MODE_PWR_DOWN and level interrupt for INT0
sei(); // must be enabled for wakeup
sleep_cpu(); // stop osc. and let INT0 do the next wakeup
cli();
}
}
MCUCR = 0x20; // SLEEP_MODE_STANDBY
PRR = 0b00001011; // USI, ADC, Timer1 aus
TCCR0B= 0x03; // Vorteiler 64 (für USB)
WDTCSR = 0x08; // Watchdog mit kürzestmöglicher Zeit (16 ms) aktivieren
PORTA = 0xF7; // grüne LED sowie Pullups EIN
DDRA = 0x0C;
PORTB = 0x09; // Pullups EIN (an offenen Eingängen)
usbInit();
sei();
for (;;) { // Endlos-Hauptschleife, wird höchstens vom Watchdog abgebrochen
uchar t=usbSofCount;
sleep_cpu(); // CPU schläft bis SOF (Ständige ISR-Abarbeitung während SE0!)
wdt_reset(); // Watchdog sollte nach 3 ms zuschnappen, Minimum des µC ist 15 ms
usbPoll();
if (!(t-SofCmp)) continue;
SofCmp=t;
Led_On1ms();
if (usbInterruptIsReady() && keychange) { // Pegelwechsel aufgetreten?
usbSetInterrupt((uchar*)&InputReport,sizeof(InputReport));
keychange=0;
}
if (!keychange) {
keychange=(~PINA&0x03)^InputReport.keystate;
if (keychange) {
if (InputReport.keystate^=keychange) {
PORTA|= 0x08; // rote LED ein
PORTA&=~0x04; // grüne LED aus
}else{
PORTA|= 0x04; // grüne LED ein
PORTA&=~0x08; // rote LED aus
}
}
}
}
}
Detected encoding: UTF-8 | 0
|