/* Name: 7key.cpp; TABSIZE=8, ENCODING=UTF-8, LINESEP=LF
* Projekt: Virtuelle Produktion
* Zweck: Abgesetzte Tablet-Tastatur für Handschuhbedienung für bestimmte Äpp
* Autor: Henrik Haftmann
*210120 erstellt
-210612 Tastenentprellzeit verlängert durch veränderten Interrupt-Endpoint-Deskriptor,
10(8) ms ist zu kurz
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/fuse.h>
#include <avr/signature.h>
#include "usbdrv.c"
FUSES={
0b11011111, // Quarz 12 MHz, schnell hochfahren, kein Taktteiler
0b01010101, // RESET als Portpin, BrownOut bei 2,7 V
0b11111111, // unverändert
};
/* Pin-Zuordnung
Pin Port Funk. Verwendung
1 Ucc 3,3 V über 2 Dioden
2 PB0 XTAL1 Quarz 12 MHz
3 PB1 XTAL2 Quarz 12 MHz
4 PB3 PCINT11 USB D-
5 PB2 USB D+
6 PA7 Taste 7: frei (alle Tasten low-aktiv)
7 PA6 Taste 6: F
8 PA5 Taste 5: P
9 PA4 Taste 4: B
10 PA3 Taste 3: X
11 PA2 Taste 2: V
12 PA1 Taste 1: C
13 PA0 Taste 0: O
14 GND Masse
Tastenanordnung:
┌────────────────────────┐
USB- │ ╔══╗ ╔══╗ ╔══╗ ╔══╗ │
Kabel │ ║ O║ ║ C║ ║ V║ ║ X║ │
══════╡ ╚══╝ ╚══╝ ╚══╝ ╚══╝ │
│ ╔══╗ ╔══╗ ╔══╗ │
│ ║ B║ ║ P║ ║ F║ │
│ ╚══╝ ╚══╝ ╚══╝ │
└────────────────────────┘
*/
// Kodezuweisungen entsprechend „USB HID Usage Tables“ (2004) Seite 53 ff.
// Hier wird ganz einfach der Tastenstatus als Bitmap (wie's von PINA kommt)
// an den PC durchgereicht; die Tastenkode-Umsetzung und die Bit-Zuordnung
// erfolgt allein mit dem Report-Beschreiber durch Windows und Linux.
// Gleichzeitige Tastendrücke sind somit gar kein Problem.
// Der Kontakt muss hinreichend prellarm sein, sonst gibt es Mehrfach-Ereignisse.
static uchar idleRate; // in 4 ms, nicht ausgewertet
static uchar keystate; // 1 = Taste gedrückt, 0 = Taste losgelassen
// USB Report-Deskriptor
// Normalerweise handelt sich es hierbei um ein „Keypad“ (Usage = 7),
// nicht um ein „Keyboard“ (Usage = 6). Bei „Keypad“ lädt zwar Win98SE korrekt
// den USB-Tastaturtreiber, aber die Tasten erscheinen funktionslos;
// jedenfalls schaltet die ScrollLock-LED der Haupt-Tastatur (PS/2) nicht.
PROGMEM const uchar usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
0x05, 0x01, // G USAGE_PAGE (Generic Desktop)
0x09, 0x06, // L USAGE (Keyboard) („Keypad“ {7} geht unter Win98 nicht, unter W2k schon.)
0xA1, 0x01, // M COLLECTION (Application)
0x05, 0x07, // G USAGE_PAGE (Keyboard)
0x75, 0x01, // G REPORT_SIZE (1)
0x95, 0x01, // G REPORT_COUNT (1)
0x15, 0x00, // G LOGICAL_MINIMUM (0)
0x25, 0x01, // G LOGICAL_MAXIMUM (1)
0x09, 'o'-93, // L USAGE (Taste O) // 93 = Differenz zwischen ASCII and USB-Usage-Kode
0x81, 0x02, // M INPUT (Var)
0x09, 'c'-93, // L USAGE (Taste C)
0x81, 0x02, // M INPUT (Var)
0x09, 'v'-93, // L USAGE (Taste V)
0x81, 0x02, // M INPUT (Var)
0x09, 'x'-93, // L USAGE (Taste X)
0x81, 0x02, // M INPUT (Var)
0x09, 'b'-93, // L USAGE (Taste B)
0x81, 0x02, // M INPUT (Var)
0x09, 'p'-93, // L USAGE (Taste P)
0x81, 0x02, // M INPUT (Var)
0x09, 'f'-93, // L USAGE (Taste F)
0x81, 0x02, // M INPUT (Var)
0x09, 0x29, // L USAGE (Taste ESC)
0x81, 0x02, // M INPUT (Var)
0xC0}; // M END_COLLECTION
#define W(x) (x)&0xFF,(x)>>8
PROGMEM const uchar usbDescriptorConfiguration[9+9+9+7] = {
9,
2, // bDescriptorType Configuration
W(sizeof usbDescriptorConfiguration),
1,
1,
0,
0x80,
3,
9,
4, // bDescriptorType Interface
0,
0,
1,
3,
0,
0,
0,
9,
0x21, // bDescriptorType HID
W(0x0101),
0,
1,
0x22,
W(sizeof usbHidReportDescriptor),
7,
5, // bDescriptorType Endpoint
0x81, // EP1IN
3, // Interrupt
W(8), // 8 Bytes
50 // Lt. oney_wdm rundet Windows auf 32 ms,
}; // das verringert das Prellen gegenüber der Vorgabe von 8 ms aus usbdrv.c
#undef W
uchar usbFunctionSetup(uchar data[8]) {
usbRequest_t *rq = (usbRequest_t*)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
usbMsgPtr = &keystate;
return 1;
}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]; // wValueH
}
} /* no vendor specific requests implemented */
return 0;
}
int main() {
uchar mcusr = MCUSR;
MCUSR = 0;
ACSR |= 0x80; // Analogvergleicher abschalten: –70µA
WDTCSR= 0x18; // Watchdog überlebt RESET: abschalten!
WDTCSR= 0;
PRR = 0b00001111; // USI, ADC, Timer0, Timer1 aus
PORTA = 0b11111111; // Pull-Up an alle Tasten
PCMSK1= 0x08; // PCINT11 aktivieren
GIMSK = 0x20;
if (mcusr & (1 << WDRF)) {
if (USBIN & USBMASK) { // no SE0 state?
MCUCR = 0x30; // SLEEP_MODE_PWR_DOWN: Quarz ausschalten
sei(); // must be enabled for wakeup
sleep_cpu(); // stop osc. and let PCINT11 do the next wakeup
cli();
}
}
MCUCR = 0x20; // SLEEP_MODE_STANDBY
usbInit();
WDTCSR= 0x08; // Watchdog mit kürzestmöglicher Zeit (16 ms) aktivieren
sei();
for (;;) { // Endlos-Hauptschleife, wird höchstens vom Watchdog abgebrochen
sleep_cpu(); // CPU schläft bis SOF
wdt_reset(); // Watchdog sollte nach 3 ms zuschnappen, Minimum des µC ist 15 ms
usbPoll();
if (usbInterruptIsReady()) { // Nach (unter Windows Windows) 32 ms
uchar chg=~PINA^keystate; // 8 Tasten abfragen
if (chg) {
keystate^=chg; // Änderungen merken
usbSetInterrupt(&keystate,1); // wird 32 ms später wirksam: Hier unkritische Verzögerung
}
}
}
}
Detected encoding: UTF-8 | 0
|