Source file: /~heha/mb-iwp/Kleinkram/7key.zip/Firmware/7key/7key.cpp

/* 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-80