Source file: /~heha/mb-iwp/Bergwerk/Not-Aus.zip/Firmware1/notaus.cpp

/* Name: notaus.cpp; TABSIZE=8, ENCODING=UTF-8, LINESEP=LF
 * Projekt: Modell 1:14 Autonome Fahrzeuge im Bergwerk
 * Zweck: Freigabe der Steuerung nur bei angestecktem USB-Gerät und gelöstem Taster
 * Autor: Henrik Haftmann
 * Auswertung: Joystick mit 2 Tasten und 0 Hebeln ausfindig machen
 * Taste0 = 1, Taste1 = 0: Not-Aus gelöst
 * Taste0 = 0, Taste1 = 1: Not-Aus gedrückt
 * Alle anderen Fälle: Fehlfunktion (bspw. Draht ab; Schaltvorgang)
*220917	erstellt
 */

#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={
  0b11000001,	// PLL-Oszillator 16 MHz, schnell hochfahren, kein Taktteiler
  0b11011101,	// BrownOut bei 2,7 V
  0b11111111,	// unverändert
};

/* Pin-Zuordnung (ähnlich FunkUsb.c)
Pin	Port	Funk.	Verwendung
1	PB5	Reset	frei
2	PB3		Rastende Taste: Low wenn gelöst
3	PB4		Rastende Taste: Low wenn gedrückt
4	GND		Masse
5	PB0		frei
6	PB1		USB D+
7	PB2		USB D-, INT0 für SOF
8	Ucc		3,3 V über 1 rote LED, die die Stromaufnahme anzeigt
*/

static uchar keystate;	// 1 = Taste gedrückt, 0 = Taste losgelassen
			// Nur Bit 0 und 1, per Hardware gegensätzlich
// USB Report-Deskriptor für Joystick
PROGMEM const uchar usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
 0x05, 1,	// G Usage Page (Generic Desktop)
 0x09, 4,	// L Usage (Joystick)
 0xA1, 1,	// M Collection (Application)
  0x05, 9,	// G Usage Page (Buttons)
  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 Tasten)
  0x19, 1,	// L  Usage Minimum (1)	= Taste 1
  0x29, 2,	// L  Usage Maximum (2)	= Taste 2
  0x81, 2,	// M  Input (Var)
  0x95, 6,	// G  Report Count (6 ungenutzte Bits)
  0x81, 1,	// M  Input (Const)
 0xC0};		// M End Collection

uchar usbFunctionSetup(uchar data[8]) {
 if (data[0]==0xA1 && data[1]==1) {
  usbMsgPtr = &keystate;
  return 1;
 }
 return 0;
}

// Diese Routine beachtet Grenzen von OSCCAL und die zwei Bereiche
// der ATtinyX5 nicht! Bis jetzt geht's trotzdem.
static void tuneOscillator(uchar ms) {
 static uchar lastTick;
#define SOLL 14	// usbSofDiff sollte 16500/8%256 = 14.5 sein
#define MABW 7	// Abweichung kleiner ±6 ist OK und wird ignoriert
 if (ms==1) {
  schar t = GPIOR1-lastTick-SOLL;	// zentriere Ergebnis um die Null
  if (t<-MABW) OSCCAL++;	// schneller machen
  if (t> MABW) OSCCAL--;	// langsamer machen
 }
 lastTick=GPIOR1;
}

int main() {
 uchar mcusr = MCUSR;
 MCUSR = 0;
 ACSR |= 0x80;		// Analogvergleicher abschalten: –70 µA
 WDTCR = 0x18;		// Watchdog überlebt RESET: abschalten!
 WDTCR = 0;
 PRR   = 0b00001011;	// USI, ADC, Timer1 aus
 PORTB = 0b00111001;	// Pull-Up an alle Eingänge
 GIMSK = 0x40;
 if (mcusr & (1 << WDRF)) {	// Wenn die Reset-Ursache der Watchdog war...
  if (USBIN & USBMASK) {	// kein SE0-State?
   MCUCR = 0x30;	// SLEEP_MODE_PWR_DOWN und Pegelinterrupt an INT0
   sei();		// Interrupts müssen für WakeUp eingeschaltet sein
   sleep_cpu();		// Oszillator anhalten, warten auf INT0-LOW-Pegel
   cli();		// INT0 aufgetreten (kann nur USB-RESET == SE0 sein)
  }
 }
 MCUCR = 0x20;		// SLEEP_MODE_STANDBY
 TCCR0B= 0x02;		// Achtel-Taktfrequenz
 usbInit();
 WDTCR = 0x08;		// Watchdog mit kürzestmöglicher Zeit (16 ms) aktivieren
 uchar sof=GPIOR0;	// SOF-Zähler modulo 256
 sei();

 for (;;) {	// Endlos-Hauptschleife, wird höchstens vom Watchdog abgebrochen
  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();
  tuneOscillator(GPIOR0-sof);
  sof = GPIOR0;
  if (usbInterruptIsReady()) {	// Nach (unter Windows) 8 ms
   uchar chg=~PINB>>3&3^keystate;	// PB3 und PB4 abfragen
// Ohne Idle-Rate kommt der anfänglich gedrückte Knopf nicht (unter Windows) an.
// Müsste eigentlich per Protokollanalyse debugt werden, aber so geht's auch.
   if (chg || !sof) {		// Idle-Rate: 256 ms
    keystate^=chg;		// Änderungen merken
    usbSetInterrupt(&keystate,1);
   }
  }
 }
}
Detected encoding: UTF-80