Source file: /~heha/mb-iwp/BootSelektor/Firmware.zip/hardware.c

/*****************************************
 * Ausgabe-Latches nibbleweise ansteuern *
 *****************************************/
#include "hardware.h"
#include <arch/avr/gcc.h>	// _NOP()
#include <dev/nvmem.h>		// NutNvMemSave()
#include <sys/timer.h>		// NutSleep()

// Kopie der Ausgabe-Latches (Startupcode setzt Null)
static u_char OutData[8];

// Alles ist in der Schaltung systematisch verkehrtherum:
// * Die LEDs sind LOW-aktiv
// * Die Bits sind vertauscht, d.h. die linke LED ist Bit 7
// * Die Latches sind vertauscht, d.h. die linke LED hängt an Latch 7
// Diese Probleme werden in den hardwarenahen Treiberfunktionen egalisiert.

// Bit-Anordnung im Byte stürzen
static u_char bitswap(u_char b) {
 u_char i,r;
 for (i=0; i<8; i++) {
  asm volatile("ror %1\n\t"
	       "rol %0\n\t"
	       :"=&r"(r)
	       :"r"(b));
 }
 return r;
}


// Ausgabetreiber initialisieren
extern void OutInit(void) {
 DDRB=DDRD=PORTD=PORTB=0xFF;
	// alles Ausgänge, alle Latches transparent, alle LEDs aus
 PORTB=0;		// alle Latches haltend
}

// Ein Byte ausgeben, dabei steuert i = 0 die linken 8 LEDs an.
// Bit 0 von b steuert die jeweils linke LED an.
// Bit-Schaltzustand: 1 = EIN und 0 = AUS
// i muss < 8 sein!
static void OutOut(u_char i, u_char b) {
 PORTD=~bitswap(b);	// LEDs sind allesamt low-aktiv
 PORTB=0x80>>i;		// Latch transparent schalten
 _NOP();
 PORTB=0;
}

static void OutUpdate(u_char i) {	// i = 0..7
 OutOut(i,OutData[i]);
}

// Alle Latches aktualisieren (bspw. nach EEPROM rücklesen)
void OutUpdateAll(void) {
 u_char i;
 for (i=0; i<8; i++) OutUpdate(i);
}

// Schaltzustand aus EEPROM laden und ausgeben
extern void OutRestore(void) {
 NutNvMemLoad(CONFOUT_EE_OFFSET,OutData,8);
 OutUpdateAll();
}

// Byte setzen und in EEPROM schreiben
static void OutSetByte(u_char i, u_char b) {
 if (i>=8) return;
 if (OutData[i]==b) return;	// nichts tun wenn unverändert
 OutData[i]=b;
 OutUpdate(i);
 NutNvMemSave(CONFOUT_EE_OFFSET+i,OutData+i,1);
}

// Nibble ausgeben
// port = 1..16 (v.l.n.r.), nibble = 0..15
static void OutSetNibble(u_char port, u_char nibble) {
 u_char i=--port>>1,b;
 if (port&1) b=(OutData[i]&0x0F)|(nibble<<4);	// High-Teil
 else b=(OutData[i]&0xF0)|(nibble&0x0F);	// Low-Teil
 OutSetByte(i,b);
}

// Bootkonfiguration wählen (von WWBMU wird nur 1-aus-4 unterstützt)
// port = 1..16, sel = 0..4 (0 = keine LED, 1..4 = LED 1-aus-4)
void OutSetBootsel(u_char port, u_char sel) {
 OutSetNibble(port,sel?1<<(sel-1):0);
}

// Angelegte Bootkonfiguration abfragen
// (so wie WWBMU es tut; das niederwertigste Bit entscheidet)
// port = 1..16, liefert 0 (kein Bit gesetzt) bis 4 (nur MSB gesetzt)
u_char OutGetBootsel(u_char port) {
 u_char b=OutData[--port>>1],r=0;
 if (port&1) b>>=4;
 b&=0x0F;
 if (b) for(;;) {
  r++;
  if (b&1) break;
  b>>=1;
 }
 return r;
}

// Eindrucksvolle Funktionsprobe
// Hinterlässt alle LEDs ausgeschaltet, ändert OutData nicht.
// Dauer: 20 ms * 128 = 2,5 Sekunden
// Mehr Zeit für Spielerei ist nicht, weil bei Stromzuschaltung
// die angeschlossenen Rechner ihre Bootkonfiguration haben wollen.
void OutKnightrider(void) {
 u_char i,b;
 for (i=0; i<8; i++) {	// von links nach rechts
  for (b=1; b; b<<=1) {
   OutOut(i,b);
   NutSleep(20);
  }
  OutOut(i,b);
 }
 for (; --i<8;) {	// von rechts nach links
  for (b=0x80; b; b>>=1) {
   OutOut(i,b);
   NutSleep(20);
  }
  OutOut(i,b);
 }
}

Detected encoding: UTF-80