Source file: /~heha/basteln/PC/DMX-Steuerung/dmx00.zip/src/dmx00.cpp

/* Aufbau des DMX-Dongles:
 Gegenüber der Schaltung aus dem Internet wurden folg}e
 funktionalen und Schaltungsveränderungen vorgenommen:
 PORTA 0 / Pin 17 / Ausgang - (wie bisher)
 PORTA 1 / Pin 18 / Eingang - AUTOFEED / Pin 14 / mit Pull-Up
 PORTA 2 / Pin 1  / Ausgang - BUSY&ACK / Pin 10&11
 PORTA 3 / Pin 2  / Eingang - STROBE / Pin 1 / mit Pull-Up
 PORTA 4 / Pin 3  / Eingang - SELIN / Pin 17 / mit Pull-Down
 PORTB / Pin 6..13 / Ein+Aus - DATA / Pin 2..9

 Das neue Mikrocontroller-Programm hat folg}e Features:
 * Steuerbarkeit von 64 Kanälen (wie bisher)
 * Speicherung der Kanal-Bytes im EEPROM
 * automatische Restauration der Kanal-Bytes beim Einschalten
 * DMX-Mindestwiederholrate 50Hz, egal bei welchem LPT-Zustand
   (via Watchdog-Timer realisiert)
 * präzises Ein-Flanken-Handshaking zur Datenübergabe
 * Rücklese-Möglichkeit über bidirektionales Parallelport
   (z.Z. ungetestet)

 Die Richtungsumschaltung (lesen oder einschreiben) erfolgt
 mit der SELIN-Leitung, LOW=schreiben, HIGH=lesen.
 Mit AUTOFEED=HIGH wird der Mikrocontroller in einen Modus
 versetzt, bei dem er "computer-hörig" wird, und quittiert
 die Empfangsbereitschaft mit BUSY=LOW. Währ} dieser
 Zeit kann er kein DMX-Signal auss}en! Bei Überschreitung
 der Zeit von ca. 18 ms wird automatisch BUSY=HIGH gesetzt
 und ein DMX-Burst ges}et.

 Mit AUTOFEED=LOW ist das Computer-Interface "taub", BUSY=HIGH,
 der Adressen-Zähler zurückgesetzt.
 Der Mikrocontroller repetiert mit seiner maximalen Frequenz.
 Nebenbei gleicht er Schritt für Schritt RAM- und EPROM-Inhalt
 ab.

 Solange BUSY=LOW ist, kann mit STROBE=LOW ein BYTE gelesen
 bzw. eingeschrieben werden; dabei wird mit BUSY=HIGH quittiert.
 Mit der Rücknahme von STROBE nach HIGH wird auch BUSY=LOW.
 Somit kann die Übertragung jedes Bytes sauber erfaßt werden,
 auch wenn der Computer schneller als der Mikrocontroller sein
 sollte.

 Vor dem Belegen von SELIN=HIGH sollte das LPT auf Eingabe
 geschaltet werden, z.B. mit dem PS/2-Modus (im ECP-Steuerregister
 PortBase+0x402 einzustellen) mit dem Bit 5 von PortBase+2.
*/
#include <windows.h>
#include <windowsx.h>
#include <setjmp.h>
#include "/henni/msvc/inpout32/inpout32.h"
#define T(x) TEXT(x)
#define elemof(x) (sizeof(x)/sizeof(*(x)))

static WORD PortBasis=0x378;                  // LPT1
static int Basisadr=1;
static BYTE Kanaele[7];
static jmp_buf jmpbuf;

static void busywait() {
 for(int i=1000; i; i--) {
  if (Inp32(PortBasis+1)&0x80) return;	/*warten bis BUSY=LOW*/
 }
 longjmp(jmpbuf,1);
}

static void putbyte(BYTE b) {
 busywait();
 Out32(PortBasis+0,b);
 Out32(PortBasis+2,Inp32(PortBasis+2)&0x1F|0x01);	// STROBE=low
 while (Inp32(PortBasis+1)&0x80);			// EXTRA: warten bis BUSY=HIGH
 Out32(PortBasis+2,Inp32(PortBasis+2)&0x1E);		// STROBE=high
}

static void PutKanaele() {
 if (!setjmp(jmpbuf)) {
  int i;
  Out32(PortBasis+2,Inp32(PortBasis+2)&0x1D|0x08);	// AUTOFEED=HIGH, SEL=LOW
  for (i=1; i<Basisadr; i++) putbyte(0);
  for (i=0; i<elemof(Kanaele); i++) putbyte(Kanaele[i]);
  for (i=Basisadr+elemof(Kanaele); i<64; i++) putbyte(0);
  Out32(PortBasis+2,Inp32(PortBasis+2)&0x1F|0x02);	// AUTOFEED=LOW
 }
}

static BYTE getbyte() {
 busywait();
 Out32(PortBasis+2,Inp32(PortBasis+2)&0x1F|0x01);	// STROBE=low
 BYTE ret=Inp32(PortBasis+0);
 while (Inp32(PortBasis+1)&0x80);			// EXTRA: warten bis BUSY=HIGH
 Out32(PortBasis+2,Inp32(PortBasis+2)&0x1E);		// STROBE=high
 return ret;
}

static bool GetKanaele() {
 if (!setjmp(jmpbuf)) {
  int i;
  Out32(PortBasis+0x402,0x20);				// PS/2-Modus
  Out32(PortBasis+2,Inp32(PortBasis+2)&0x15|0x20);	// AUTOFEED=HIGH, SEL=HIGH, INPUT
  for (i=1; i<Basisadr; i++) getbyte();
  for (i=0; i<elemof(Kanaele); i++) Kanaele[i]=getbyte();
/*  for (i=Basisadr+elemof(Kanaele); i<64; i++) getbyte();*/
  Out32(PortBasis+2,Inp32(PortBasis+2)&0x1F|0x0A);	// AUTOFEED=LOW, SEL=LOW, OUTPUT
  return true;
 }
 return false;
}

static void ShowPos(HWND Wnd, int NewPos) {
/*Setzt die Position im Edit-Fenster und am DMX-Dongle, mithin am Scanner
 Wnd ist das Handle des sendenden Rollbalkens*/
 UINT id=GetDlgCtrlID(Wnd);
 SetDlgItemInt(GetParent(Wnd),id+elemof(Kanaele),NewPos,true);
 Kanaele[id-101]=NewPos;
 PutKanaele();
}

static void Roll(HWND Wnd, int RollDiff) {
 RollDiff+=GetScrollPos(Wnd,SB_CTL);
 if (RollDiff<0) RollDiff=0;
 if (RollDiff>255) RollDiff=255;
 SetScrollPos(Wnd,SB_CTL,RollDiff,true);
 ShowPos(Wnd,RollDiff);
}

static BOOL CALLBACK MainDlgProc(HWND Wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
 switch (msg) {
  case WM_INITDIALOG: {
   if (!GetKanaele()) MessageBox(Wnd,T("Box reagiert nicht"),NULL,0);
   for (int i=0; i<elemof(Kanaele); i++) {
    HWND w=GetDlgItem(Wnd,i+101);
    SetScrollRange(w,SB_CTL,0,255,false);
    SetScrollPos(w,SB_CTL,Kanaele[i],false);
    SetDlgItemInt(Wnd,i+108,Kanaele[i],true);
   }
  }return TRUE;

  case WM_COMMAND: switch (LOWORD(wParam)) {
   case 2: EndDialog(Wnd,0); break;
  }break;

  case WM_VSCROLL: switch (LOWORD(wParam)) {
   case SB_LINEUP: Roll((HWND)lParam,-4); break;
   case SB_LINEDOWN: Roll((HWND)lParam,4); break;
   case SB_PAGEUP: Roll((HWND)lParam,-32); break;
   case SB_PAGEDOWN: Roll((HWND)lParam,32); break;
   case SB_THUMBTRACK:
   case SB_THUMBPOSITION: {
    SetScrollPos((HWND)lParam,SB_CTL,HIWORD(wParam),true);
    ShowPos((HWND)lParam,HIWORD(wParam));
   }break;
  }
 }
 return FALSE;
}

int CALLBACK WinMainCRTStartup() {
 return DialogBox(0,MAKEINTRESOURCE(100),0,MainDlgProc);
}
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded