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