#define WIN32_LEAN_AND_MEAN #define STRICT #define WINVER 0x0500 #include #include #include #ifdef WIN32 // Win32 wird zurzeit mit MSVC6 übersetzt #include #include #pragma comment(linker, "/NOD /OPT:NOWIN98 /ALIGN:4096 /RELEASE") #else // Win16 wird zurzeit mit BC4 übersetzt #include #include typedef char TCHAR,*PTSTR,FAR*LPTSTR,NEAR*NPTSTR; typedef void *PVOID,FAR*LPVOID,NEAR*NPVOID; #define TEXT(x) x #define _stdcall _cdecl // gleiche Parameter-Reihenfolge! #define MAKEPOINTS MAKEPOINT #endif #define elemof(x) (sizeof(x)/sizeof(*(x))) #define T(x) TEXT(x) #define nobreak typedef enum {false,true} bool; typedef const TCHAR *PCTSTR; #ifdef WIN32 int InOutMeth=3; // 0=direkt, 1=ZLPORTIO, 2=EZUSB-0, 3=(USB2)LPT2 #endif //static POINT Pins[25]; BYTE LptRegsRd[16]; BYTE LptRegsWr[16]; HWND hwndTT; HANDLE hAccess=INVALID_HANDLE_VALUE; //Direktzugriff aufs Port UINT LptBase=0x378; UINT Index2Addr(int a) { // Index (0..15) in Parallelportadresse wandeln return LptBase+(a<8?a:a-8+0x400); } void outb(int a, BYTE b) { LptRegsWr[a]=b; // vermerken #ifdef WIN32 switch (InOutMeth){ case 0:{ // Direktzugriff (Win9x) a=Index2Addr(a); _asm{ mov edx,a mov al,b out dx,al } }break; case 1:{ // ZLPORTIO DWORD IoData[3]={Index2Addr(a),0,b}; // Byte=0, igitt! DWORD BytesRet; DeviceIoControl(hAccess,CTL_CODE(0x80FF,2,METHOD_BUFFERED,FILE_ANY_ACCESS), IoData,sizeof(IoData),NULL,0,&BytesRet,NULL); }break; case 2:{ // EZUSB-0 DWORD PipeNum; BYTE IoData[2]; DWORD BytesRet; IoData[0]=(BYTE)a; IoData[1]=b; PipeNum=0; DeviceIoControl(hAccess, CTL_CODE(FILE_DEVICE_UNKNOWN,0x814,METHOD_IN_DIRECT,FILE_ANY_ACCESS), &PipeNum,sizeof(PipeNum),IoData,sizeof(IoData),&BytesRet,NULL); }break; case 3:{ // LPTx BYTE IoData[2]; DWORD BytesRet; IoData[0]=(BYTE)a; IoData[1]=b; DeviceIoControl(hAccess, CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED,FILE_ANY_ACCESS), IoData,sizeof(IoData),NULL,0,&BytesRet,NULL); }break; } #else outportb(Index2Addr(a),b); #endif } BYTE inb(int a) { #ifdef WIN32 switch (InOutMeth){ case 0:{ // Direktzugriff (Win9x) a=Index2Addr(a); _asm{ mov edx,a in al,dx mov a,eax } }break; case 1:{ // ZLPORTIO DWORD IoData[3]={Index2Addr(a),0}; DWORD BytesRet; DeviceIoControl(hAccess,CTL_CODE(0x80FF,1,METHOD_BUFFERED,FILE_ANY_ACCESS), IoData,sizeof(IoData),&IoData[2],sizeof(DWORD),&BytesRet,NULL); a=IoData[2]; }break; case 2:{ // EZUSB-0 DWORD PipeNum; BYTE IoData[1]; DWORD BytesRet; IoData[0]=(BYTE)a|0x10; // Lese-Bit PipeNum=0; DeviceIoControl(hAccess, CTL_CODE(FILE_DEVICE_UNKNOWN,0x814,METHOD_IN_DIRECT,FILE_ANY_ACCESS), &PipeNum,sizeof(PipeNum),IoData,sizeof(IoData),&BytesRet,NULL); PipeNum=1; Sleep(1); DeviceIoControl(hAccess, CTL_CODE(FILE_DEVICE_UNKNOWN,0x813,METHOD_OUT_DIRECT,FILE_ANY_ACCESS), &PipeNum,sizeof(PipeNum),IoData,sizeof(IoData),&BytesRet,NULL); a=IoData[0]; }break; case 3:{ // LPTx BYTE IoData[1]; DWORD BytesRet; IoData[0]=(BYTE)a|0x10; // Lese-Bit DeviceIoControl(hAccess, CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED,FILE_ANY_ACCESS), IoData,sizeof(IoData),IoData,sizeof(IoData),&BytesRet,NULL); a=IoData[0]; }break; } return a; #else return inportb(Index2Addr(a)); #endif } #undef ZeroMemory void WINAPI ZeroMemory(LPVOID p, UINT len) { #ifdef WIN32 _asm{ push edi mov edi,p mov ecx,len shr ecx,2 xor eax,eax rep stosd pop edi } #else _asm{ push di les di,p mov cx,len shr cx,1 xor ax,ax rep stosw pop di } #endif } void InitStruct(PVOID p, UINT len) { ZeroMemory(p,len); *(PDWORD)p=len; } static const BYTE PinAssign[25]={ // High-Nibble=Adresse, Low-Nibble=BitNr, Bit3=Inv 0x28,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x16,0x1F,0x15,0x14, 0x29,0x13,0x22,0x2B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; static const COLORREF PinColor[3]={0x00FF00,0x0000FF,0x00E0E0}; // Was für ein Zufall! WinDriver verwendet die gleichen Farben wie LptChk! // Pin-Bezeichnungen mit Invertierungsschrägstrich - aus Sicht der Software! static const TCHAR SppS[]=T("/BUSY (beschäftigt)\0/ACK (Bestätigung)\0PE (Papierende)\0SEL (Auswahl)\0/ERR (Fehler)\0/IRQ (Interruptanforderung)\0"); // 6 Bits static const TCHAR SppC[]=T("STB (Strobe)\0AF (AutoFeed)\0/INI (Init, Rücksetzen)\0SELIN (Select Input, Auswahl)\0IRQEN (Interruptfreigabe)\0DIRIN (Datenrichtung: Eingabe)\0"); // 6 Bits static const TCHAR BytS[]="PtrBusy\0PtrClk\0AckDataReq\0Xflag\0/DataAvail"; // 5 Bits static const TCHAR BytC[]="1284Active\0/Init\0HostBusy\0HostClk"; // 4 Bits static const TCHAR NibS[]="R3\0PtrClk\0R2\0R1\0R0"; static const TCHAR EcpS[]=T("PeriphAck\0PeriphClk\0/AckReverse\0Xflag\0/PeriphRequest\0"); static const TCHAR EcpC[]=T("HostClk\0HostAck\0/ReverseRequest\0001284Active\0"); static const TCHAR EppS[]="/Wait\0/Intr\0Spare\0Spare\0Spare\0-\0-\0Timeout\0"; // 2 Bits static const TCHAR EppC[]="Write\0DataStb\0/Reset\0AddrStb\0"; // 4 Bits //ECR-Modes für Kombinationsfenster static const TCHAR EcrMode[]=T("SPP (Nibble)\0Bidirektional\0AutoStrobe\0ECP\0EPP\0reserviert\0Test\0Konfiguration\0"); struct { HPEN ColorPen[3]; HBRUSH ColorBrush[3]; HPEN WidePen; HPEN AirwirePen; HPEN NullPen; HFONT SmallFont; HFONT DescFont; }gdi; enum{ SubDPosX =50, // Position linke obere Ecke (am wirklichen Pin 13... SubDPosY =92, // beim Blick auf die Buchsen-Löcher SubDSpaceX=16, // Pin-Abstand (in Wahrheit 53 mil), muss hier gerade sein SubDSpaceY=16, // Reihenabstand SubDPinD =10, // Durchmesser, muss gerade sein SubDRand =12, // Abstand zum Rand (von den Mittelpunkten der Pins) SubDRandW =3 // Strichbreite für Umrandung }; static void CreateGdiResources(void) { int i; for (i=0; i<3; i++) { gdi.ColorPen[i]=CreatePen(PS_SOLID,0,PinColor[i]); gdi.ColorBrush[i]=CreateSolidBrush(PinColor[i]); } gdi.WidePen=CreatePen(PS_SOLID,SubDRandW,0); gdi.AirwirePen=CreatePen(PS_SOLID,0,0xFF0000L); gdi.NullPen=CreatePen(PS_NULL,0,0); gdi.SmallFont=CreateFont(-7,0,0,0,0,0,0,0,0,0,0,0,0,T("Small Fonts")); gdi.DescFont=CreateFont(-10,0,0,0,0,0,0,0,0,0,0,0,0,T("Helv")); } static void DeleteGdiResources(void) { int i; for (i=0; ileft=rc->right=pt->x; rc->top=rc->bottom=pt->y; InflateRect(rc,dx,dy); } /*================ SubD-Buchse ================*/ static void GetPinPos(BYTE pin, PPOINT pt) { // Pins sind 0-basiert pt->x=SubDPosX+SubDRand+SubDSpaceX*(12-pin); pt->y=SubDPosY+SubDRand; if (pin>=13) { pt->x+=SubDSpaceX*25/2; pt->y+=SubDSpaceY; } } static void GetPinRect(BYTE pin, PRECT rc) { // gut für Treffertest POINT pt; GetPinPos(pin,&pt); InflatePoint(&pt,rc,SubDPinD/2,SubDPinD/2); } // pin=SubD-Pin-Nummer! BorlandC verlangt ein paar überflüssige Klammern static void DrawPin(HDC dc, BYTE pin) { RECT rc; HPEN hOldPen; HBRUSH hOldBrush; BYTE PinAss=PinAssign[pin]; BYTE PinHigh; int PortIndex=(signed char)(PinAss&0xF0)>>4; GetPinRect(pin,&rc); if (PortIndex>=0) { hOldPen=SelectPen(dc,gdi.ColorPen[PortIndex]); PinHigh=LptRegsRd[PortIndex]&(1<<(PinAss&7)); if (PinAss&8) PinHigh=!PinHigh; if (PinHigh) hOldBrush=SelectBrush(dc,gdi.ColorBrush[PortIndex]); } Ellipse(dc,rc.left,rc.top,rc.right,rc.bottom); if (PortIndex>=0) { SelectPen(dc,hOldPen); if (PinHigh) SelectBrush(dc,hOldBrush); } } static void DrawPinNumber(HDC dc, BYTE pin) { POINT pt; TCHAR nr[3]; GetPinPos(pin,&pt); TextOut(dc,pt.x+2,pt.y-SubDRand+1,nr,wsprintf(nr,T("%i"),pin+1)); } static void DrawSubD(HDC dc) { // SubD-Buchse malen (nur Schale) HPEN hOld; static const POINT Poly[6]={ {SubDPosX+SubDSpaceX*12+SubDRand*2, SubDPosY}, {SubDPosX+SubDSpaceX*12+SubDRand*2, SubDPosY+SubDRand+SubDSpaceY/2}, {SubDPosX+SubDSpaceX*23/2+SubDRand*2, SubDPosY+SubDRand*2+SubDSpaceY}, {SubDPosX+SubDSpaceX/2, SubDPosY+SubDRand*2+SubDSpaceY}, {SubDPosX, SubDPosY+SubDRand+SubDSpaceY/2}, {SubDPosX, SubDPosY}}; hOld=SelectPen(dc,gdi.WidePen); Polygon(dc,Poly,elemof(Poly)); SelectPen(dc,hOld); } static void DrawPins(HDC dc) { // SubD-Pins malen BYTE pin; HFONT hOld; hOld=SelectFont(dc,gdi.SmallFont); SetBkMode(dc,TRANSPARENT); pin=0; do{ DrawPin(dc,pin); DrawPinNumber(dc,pin); }while (++pin<25); SetBkMode(dc,OPAQUE); SelectFont(dc,hOld); } #ifdef _BORLANDC_ # pragma argsused #endif static bool _stdcall HitTestPin(int x, int y, BYTE*ppin) { BYTE pin; for (pin=0; pin<17; pin++) { RECT rc; GetPinRect(pin,&rc); if (PtInRect(&rc,*((PPOINT)&x))) { if (ppin) *ppin=pin; return true; } } return false; } /*================ Bit-Kästchen ================*/ /************************************************************************ * Mittelpunkt eines der 24 Bit-Kästchen beschaffen * bit = Bitadresse: aaaaibbb (aaaa=Portadresse, i=Invers, bbb=Bitnummer) ************************************************************************/ static void GetBitPos(BYTE bit, PPOINT ppt) { static const POINT bit7[3]={ // Positionen des Bit 7 (der drei Bitketten) {SubDPosX+SubDRand+SubDSpaceX*4, SubDPosY-30}, {SubDPosX+SubDSpaceX*4/2, SubDPosY+SubDRand*2+SubDSpaceY+40}, {SubDPosX+SubDRand+SubDSpaceX*11/2, SubDPosY+SubDRand*2+SubDSpaceY+80}}; *ppt=bit7[bit>>4]; ppt->x+=(7-(bit&7))*SubDSpaceX; } /************************************************************************ * Zeichenrechteck eines der 24 Bit-Kästchen beschaffen * bit = Bitadresse: aaaaibbb (aaaa=Portadresse, i=Invers, bbb=Bitnummer) ************************************************************************/ static void GetBitRect(BYTE bit, PRECT rc) { POINT pt; GetBitPos(bit,&pt); InflatePoint(&pt,rc,SubDSpaceX/2,SubDSpaceY/2); } /************************************************************************ * Bitadresse in SubD-Pinnummer (0-basiert!) umrechnen * bit = Bitadresse: aaaaibbb (aaaa=Portadresse, i=Invers, bbb=Bitnummer) * Liefert wenn Bitadresse keiner SubD-Pinnummer entspricht ************************************************************************/ static bool FindPin(BYTE bit, BYTE*ppin) { BYTE pin; for (pin=0; pin<25; pin++) { if (!((bit^PinAssign[pin])&0xF7)) { // Wenn sich aaaa und bbb gleichen if (ppin) *ppin=pin; return true; } } return false; } /************************************************************************ * Zeichne ein Bit-Kästchen * bit = Bitadresse: aaaaibbb (aaaa=Portadresse, i=Invers, bbb=Bitnummer) * LptRegsRd und LptRegsWr müssen die richtigen Werte bereits enthalten. ************************************************************************/ static void DrawBit(HDC dc, BYTE bit) { int PortIndex=bit>>4; BYTE Mask,BitHighRd,BitHighWr; RECT rc; HBRUSH hOldBrush; BYTE pin; Mask=1<<(bit&7); BitHighRd=LptRegsRd[PortIndex]&Mask; BitHighWr=LptRegsWr[PortIndex]&Mask; GetBitRect(bit,&rc); if (BitHighRd|BitHighWr) hOldBrush=SelectBrush(dc,gdi.ColorBrush[PortIndex]); Rectangle(dc,rc.left,rc.top,rc.right,rc.bottom); if (BitHighRd|BitHighWr) SelectBrush(dc,hOldBrush); if (BitHighRd^BitHighWr) { HPEN hOld=SelectPen(dc,gdi.NullPen); POINT pt[3]; CopyRect((PRECT)pt,&rc); InflateRect((PRECT)pt,-1,-1); pt[2].x=pt[1].x; pt[2].y=pt[0].y; if (BitHighRd) pt[0].y=pt[1].y; else pt[1].x=pt[0].x; Polygon(dc,pt,3); // weißes Dreieck zeichnen SelectPen(dc,hOld); } if (FindPin(bit,&pin)) { HFONT hOld; TCHAR Buf[3]; int Dx=SubDSpaceX/2-1; // Position der Ziffer (2. Zeichen) bit=PinAssign[pin]; hOld=SelectFont(dc,gdi.DescFont); SetBkMode(dc,TRANSPARENT); ExtTextOut(dc,rc.left+1,rc.top+2,ETO_CLIPPED,&rc,Buf,wsprintf(Buf,T("%c%d"), T("DSC")[bit>>4],bit&7),&Dx); SetBkMode(dc,OPAQUE); SelectFont(dc,hOld); if (bit&8) { // Invertierung? POINT pt[2]; // BorlandC verträgt keine nicht-konstanten pt[0].x=rc.left+2; // Initialisierer (C-konform; unpraktisch) pt[0].y=rc.top+2; pt[1].x=rc.right-2; pt[1].y=rc.top+2; Polyline(dc,pt,2); // Überstrich zeichnen } } } /************************************************************************ * Zeichne alle 8 Bit-Kästchen eines Bytes * bit = Bitadresse: aaaa0--- (aaaa=Portadresse) ************************************************************************/ static void DrawByte(HDC dc, BYTE bit) { // Bit-Felder malen for (; !(bit&8); bit++) { DrawBit(dc,bit); } } /************************************************************************ * Zeichne alle (17) Luftlinien ************************************************************************/ static void DrawAirwires(HDC dc) { HPEN hOld; BYTE pin; hOld=SelectPen(dc,gdi.AirwirePen); for (pin=0; pin<17; pin++) { POINT pt[2]; GetPinPos(pin,pt+0); GetBitPos(PinAssign[pin],pt+1); pt[1].y-=SubDSpaceY/2; // oben ansetzen Polyline(dc,pt,2); } SelectPen(dc,hOld); } /************************************************************************ * Treffertest für die 24 Bit-Kästchen * Liefert bei Treffer und ggf. die "Bitadresse" in *pb ************************************************************************/ #ifdef _BORLANDC_ # pragma argsused #endif static bool _stdcall HitTestBit(int x, int y, BYTE*pbit) { BYTE bit; for (bit=0; bit<0x30; ) { RECT rc; GetBitRect(bit,&rc); if (PtInRect(&rc,*((PPOINT)&x))) { if (pbit) *pbit=bit; return true; } bit++; if (bit&8) bit+=8; // Bit 3 (Negativ-Bit) überspringen } return false; } /************************************************************************ * Knöpfe zur Datenein/Ausgabe aktivieren/deaktivieren * Dialogelemente füllen ************************************************************************/ static void SetEcrMode(HWND Wnd, int Mode){ static const BYTE Info[8]={0x52,0x52,0x52,0xDF,0x5F,0x02,0x57,0x11}; BYTE Inf=Info[Mode]; HWND w; // Info-Bits: Bit0: Eingabe-Byte sichtbar // 1: Eingabe-Byte readonly, sonst "cfgA" und "cfgB" sichbar // 2: Eingabe-Knopf sichtbar // 3: Radiobuttons sichtbar // 4: Ausgabe-Byte sichtbar // 5: Ausgabe-Byte readonly // 6: Ausgabe-Knopf sichtbar // 7: Radiobutton-Ersatztext "Komm&ando" statt "&Adresse" SendDlgItemMessage(Wnd,102,CB_SETCURSEL,Mode,0); w=GetDlgItem(Wnd,168); // Eingabe-Byte ShowWindow(w,Inf&0x01?SW_SHOW:SW_HIDE); (void)Edit_SetReadOnly(w,Inf&0x02); w=GetDlgItem(Wnd,131); // Eingabe-Knopf ShowWindow(w,Inf&0x04?SW_SHOW:SW_HIDE); w=GetDlgItem(Wnd,122); // Radioknopf "Adresse" ShowWindow(w,Inf&0x08?SW_SHOW:SW_HIDE); SetWindowText(w,Inf&0x80?T("Komm&ando"):T("&Adresse")); w=GetWindow(w,GW_HWNDNEXT); ShowWindow(w,Inf&0x08?SW_SHOW:SW_HIDE); w=GetDlgItem(Wnd,130); // Ausgabe-Knopf ShowWindow(w,Inf&0x40?SW_SHOW:SW_HIDE); w=GetDlgItem(Wnd,169); // Ausgabe-Byte ShowWindow(w,Inf&0x10?SW_SHOW:SW_HIDE); (void)Edit_SetReadOnly(w,Inf&0x20); w=GetDlgItem(Wnd,118); // Text "CfgA" ShowWindow(w,Inf&0x02?SW_HIDE:SW_SHOW); w=GetDlgItem(Wnd,119); // Text "CfgB" ShowWindow(w,Inf&0x02?SW_HIDE:SW_SHOW); switch (Mode){ case 7:{ // Konfigurationsmodus: cfgA und cfgB lesen LptRegsRd[8]=inb(8); SetDlgItemHex(Wnd,168,LptRegsRd[8]); KillTimer(Wnd,168); LptRegsRd[9]=inb(9); SetDlgItemHex(Wnd,169,LptRegsRd[9]); KillTimer(Wnd,169); }break; } w=GetDlgItem(Wnd,117); // Knopf "lesen" (für Datenport +0) ShowWindow(w,Mode<2||Mode==4?SW_HIDE:SW_SHOW); } static void OnOutputButton(HWND Wnd){ int Mode=(int)SendDlgItemMessage(Wnd,102,CB_GETCURSEL,0,0); UINT u; BYTE b; HDC dc; if (GetDlgItemHex(Wnd,169,&u) && u<256){ b=(BYTE)u; switch (Mode){ case 0: case 1:{ outb(0,b); // Datenbyte anlegen outb(2,(BYTE)(LptRegsWr[2]|0x01)); // Strobe generieren outb(2,(BYTE)(LptRegsWr[2]&~0x01)); goto xxx; }break; case 2:{ outb(0,b); SetDlgItemHex(Wnd,160,b); KillTimer(Wnd,160); }break; //SPP-FIFO case 3: // ECP outb(IsDlgButtonChecked(Wnd,122)?0:8,b); break; // Kommando:0, Daten:400h case 4:{ // EPP outb(IsDlgButtonChecked(Wnd,122)?3:4,b); // Adresse:3, Daten:4 LptRegsWr[0]=b; // automatisch xxx: dc=GetDC(Wnd); DrawByte(dc,0x00); ReleaseDC(Wnd,dc); SetDlgItemHex(Wnd,160,b); KillTimer(Wnd,160); }break; case 6: outb(8,b); break; // Test: 400h } b++; // ein anderes Datenbyte anbieten (ist zweckmäßig!) SetDlgItemHex(Wnd,169,b); KillTimer(Wnd,169); }else{ MessageBeep(MB_ICONEXCLAMATION); SetFocus(GetDlgItem(Wnd,169)); } Edit_SetSel(GetDlgItem(Wnd,169),0,-1); } static void OnInputButton(HWND Wnd){ int Mode=(int)SendDlgItemMessage(Wnd,102,CB_GETCURSEL,0,0); BYTE b; switch (Mode){ case 3: b=inb(IsDlgButtonChecked(Wnd,122)?0:8); break; // ECP case 4: b=inb(IsDlgButtonChecked(Wnd,122)?3:4); break; // ECP case 6: b=inb(8); break; default: return; } SetDlgItemHex(Wnd,168,b); KillTimer(Wnd,168); } static void update(HWND Wnd, int a){ // Portadresse lesen und Darstellung aktualisieren BYTE b=inb(a); if (b==LptRegsRd[a]) return; switch (a) { case 0: case 1: case 2: { BYTE m,bit,pin; HDC dc=GetDC(Wnd); for (m=1,bit=a<<4; m; m<<=1,bit++) { if ((LptRegsRd[a]^b)&m) { LptRegsRd[a]^=m; DrawBit(dc,bit); // Bit-Kästchen aktualisieren if (FindPin(bit,&pin)) DrawPin(dc,pin); // Pin-Kreis aktualisieren } } ReleaseDC(Wnd,dc); SetDlgItemHex(Wnd,176+a,b); // Hexadezimalanzeige aktualisieren }break; case 8: // cfgA case 9:{ // cfgB SetDlgItemHex(Wnd,160+a,b); // Hexadezimalanzeige aktualisieren KillTimer(Wnd,160+a); LptRegsRd[a]=b; }break; case 10:{ // ECR (+402) if ((LptRegsRd[10]^b)&0x01) CheckDlgButton(Wnd,121,b&0x01); if ((LptRegsRd[10]^b)&0x02) CheckDlgButton(Wnd,120,(b>>1)&0x01); if ((LptRegsRd[10]^b)&0xE0) SetEcrMode(Wnd,b>>5); SetDlgItemHex(Wnd,176+a,b); // Hexadezimalanzeige aktualisieren }nobreak; default: LptRegsRd[a]=b; } } // Ein zu schreibendes Bit ("Bitnummer" b) kippen static void ToggleBit(HWND Wnd, BYTE b) { HDC dc=GetDC(Wnd); int i; i=b>>4; outb(i,(BYTE)(LptRegsWr[i]^(1<<(b&7)))); // neues Byte ausgeben SetDlgItemHex(Wnd,160+i,LptRegsWr[i]); // anzeigen KillTimer(Wnd,160+i); // EN_CHANGE abwürgen DrawBit(dc,b); // anzeigen ReleaseDC(Wnd,dc); update(Wnd,i); // gleiche Adresse einlesen } static void ToggleAt(HWND Wnd, int x, int y) { BYTE bit,pin; if (HitTestPin(x,y,&pin)) ToggleBit(Wnd,PinAssign[pin]); else if (HitTestBit(x,y,&bit)) ToggleBit(Wnd,bit); } void GetMousePos(HWND Wnd, PPOINT ppt) { //ermittelt Mauskordinaten der letzten Nachricht #ifdef WIN32 DWORD dw=GetMessagePos(); ppt->x=MAKEPOINTS(dw).x; ppt->y=MAKEPOINTS(dw).y; #else *(PDWORD)ppt=GetMessagePos(); #endif ScreenToClient(Wnd,ppt); } static PCTSTR Index2String(PCTSTR p, int i) { // Gegenfunktion, liefert String zum Index, NULL wenn ungültig for (;*p;p+=lstrlen(p)+1,i--) if (!i) return p; return NULL; } static PCTSTR Index2String2(PCTSTR p1, PCTSTR p2, int i) { //Probiere erst p1, wenn's nicht klappt, dann p2: PCTSTR p=Index2String(p1,i); if (p) return p; return Index2String(p2,i); } typedef union{ // aktueller Hit-Test (gesetzt von WM_SetCursor) struct{ BYTE bit; // 0xFF = kein Treffer BYTE pin; // 0xFF = kein Treffer }u; WORD both; // 0xFFFF = kein Treffer }THitTest,*PHitTest; THitTest gHitTest; // enthält Treffertest nach WM_SetCursor static void GetBubblehelpText(HWND Wnd, LPTSTR buf, UINT buflen) { int Mode; BYTE bit,inv=0; PCTSTR AltS,AltC,ps=NULL; // Alternative Strings TCHAR s[8]; buf[0]=0; if (gHitTest.both==0xFFFF) return; Mode=(int)SendDlgItemMessage(Wnd,102,CB_GETCURSEL,0,0); switch (Mode){ case 2: AltS=BytS; AltC=BytC; break; // Autostrobe case 3: AltS=EcpS; AltC=EcpC; break; // ECP case 4: AltS=EppS; AltC=EppC; break; // EPP default:AltS=SppS; AltC=SppC; } bit=gHitTest.u.bit; // Treffer am Bit? if (bit==0xFF){ bit=PinAssign[gHitTest.u.pin];// Treffer am Pin! inv=bit&0x08; bit&=0xF7; } switch (bit>>4){ case 0:{ wsprintf(s,T("Data %u"),bit); ps=s; }break; case 1:{ ps=Index2String2(AltS,SppS,0x17-bit);// von oben }break; case 2:{ ps=Index2String2(AltC,SppC,bit-0x20);// von unten }break; } if (!ps) return; // Invertierungen am Pin umkehren if (inv){ if (*ps==T('/')) ps++; // Invertierungsstrich am Signalnamen entfernen else if (buflen){ *buf++=T('/'); // Invertierungsstrich hinzufügen buflen--; } } lstrcpyn(buf,ps,buflen); } void ReadPorts(void) { BYTE a; for (a=0; a<16; a++) LptRegsRd[a]=~(LptRegsWr[a]=inb(a)); // erst das Gegenteil einschreiben, dann updaten lassen } BOOL CALLBACK MainDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch (Msg) { case WM_INITDIALOG:{ TOOLINFO ti; PCTSTR p; HWND w=GetDlgItem(Wnd,102); for(p=EcrMode;*p;p+=lstrlen(p)+1){ (void)ComboBox_AddString(w,p); } ReadPorts(); CreateGdiResources(); InitCommonControls(); hwndTT=CreateWindow(TOOLTIPS_CLASS, NULL, WS_POPUP,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,0,0,NULL); InitStruct(&ti,sizeof(ti)); ti.uFlags=TTF_TRACK|TTF_CENTERTIP; ti.hwnd=Wnd; ti.uId=(UINT)Wnd; ti.lpszText=LPSTR_TEXTCALLBACK; SendMessage(hwndTT,TTM_ADDTOOL,0,(LPARAM)&ti); CheckDlgButton(Wnd,122,TRUE); //"Adresse" auswählen SetTimer(Wnd,1,100,NULL); }return TRUE; case WM_TIMER: switch (wParam){ case 1:{ // zyklisches Update int Mode=LptRegsRd[10]>>5; if (Mode<2 || Mode==4) update(Wnd,0); // im ECP-Modus kein Auslesen! (Test?) // Im Autostrobe-Modus und im Testmodus bewirkt das Lesen von Adresse+0 // das Leeren der FIFO (am Rechner "Mixer"): undokumentiert! // Bei Autostrobe wartet die FIFO auf BUSY=LOW update(Wnd,1); update(Wnd,2); if (Mode==7){ // Nur im Testmodus automatisch auslesen update(Wnd,8); update(Wnd,9); } update(Wnd,10); }break; case 160: case 161: case 162: case 168: case 169: case 170:{ // Editfeld geändert: automatische Byte-Ausgabe UINT v; KillTimer(Wnd,wParam); // nicht-zyklisch! if (wParam==169 && (LptRegsRd[10]&0xE0)!=0xE0) { OnOutputButton(Wnd); // Abzweigen zum Äquivalent des Knopfdrückens break; } SendDlgItemMessage(Wnd,wParam,EM_SETSEL,0,(LPARAM)-1); // alles markieren if (GetDlgItemHex(Wnd,wParam,&v)){ wParam-=160; if (LptRegsWr[wParam]!=v){ outb(wParam,(BYTE)v); // setzt LptRegsWr if (wParam<3){ HDC dc=GetDC(Wnd); DrawByte(dc,(BYTE)(wParam<<4)); ReleaseDC(Wnd,dc); } } }else MessageBeep(MB_ICONEXCLAMATION); }break; }break; case WM_PAINT:{ PAINTSTRUCT PS; BeginPaint(Wnd,&PS); DrawSubD(PS.hdc); DrawAirwires(PS.hdc); DrawPins(PS.hdc); DrawByte(PS.hdc,0x00); DrawByte(PS.hdc,0x10); DrawByte(PS.hdc,0x20); EndPaint(Wnd,&PS); }break; case WM_SETCURSOR:{ POINT pt; TOOLINFO ti; THitTest ht; InitStruct(&ti,sizeof(ti)); ti.hwnd=Wnd; ti.uId=(UINT)Wnd; GetMousePos(Wnd,&pt); ht.both=0xFFFF; HitTestPin(pt.x,pt.y,&ht.u.pin); HitTestBit(pt.x,pt.y,&ht.u.bit); if (ht.both!=0xFFFF){ SetCursor(LoadCursor(0,IDC_HAND)); if (gHitTest.both!=ht.both){ gHitTest=ht; SendMessage(hwndTT,TTM_TRACKACTIVATE,TRUE,(LPARAM)&ti); SendMessage(hwndTT,TTM_TRACKPOSITION,0,MAKELONG(pt.x,pt.y)); } return TRUE; } if (gHitTest.both!=0xFFFF){ gHitTest=ht; SendMessage(hwndTT,TTM_TRACKACTIVATE,FALSE,(LPARAM)&ti); } }break; case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:{ ToggleAt(Wnd,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y); }break; case WM_NOTIFY:{ #define ttt ((LPNMTTDISPINFO)lParam) switch (ttt->hdr.code) { case TTN_GETDISPINFO: { GetBubblehelpText(Wnd,ttt->szText,elemof(ttt->szText)); //ttt->lpszText=ttt->szText; }break; } #undef ttt }break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDCANCEL: EndDialog(Wnd,LOWORD(wParam)); break; case 102: switch (GET_WM_COMMAND_CMD(wParam,lParam)) { case CBN_SELCHANGE: { int Mode=ComboBox_GetCurSel((HWND)lParam); outb(10,(BYTE)((LptRegsWr[10]&0x1F)|(Mode<<5))); SetDlgItemHex(Wnd,170,LptRegsWr[10]); KillTimer(Wnd,170); }break; }break; case 117: update(Wnd,0); break; // Knopf "Lesen" für Datenport (+0) case 160: case 161: case 162: case 168: // Eingabe-Byte: Nur editierbar im Konfigurationsmodus (cfgA) case 169: // Ausgabe-Byte oder cfgB case 170: switch (GET_WM_COMMAND_CMD(wParam,lParam)) { case EN_CHANGE: SetTimer(Wnd,LOWORD(wParam),500,NULL); break; }break; case 131: OnInputButton(Wnd); break; case 130: OnOutputButton(Wnd); break; }break; case WM_DESTROY:{ DeleteGdiResources(); }break; } return FALSE; } #ifdef WIN32 int WINAPI WinMainCRTStartup() { PCTSTR DevName=NULL; switch (InOutMeth){ case 1: DevName=T("\\\\.\\ZLPORTIO"); break; // Dienst muss gestartet werden! case 2: DevName=T("\\\\.\\EZUSB-0"); break; case 3: DevName=T("\\\\.\\LPT2"); break; } if (DevName) hAccess=CreateFile(DevName, GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0); DialogBox(0,MAKEINTRESOURCE(100),0,MainDlgProc); if (hAccess!=INVALID_HANDLE_VALUE) CloseHandle(hAccess); return 0; } #else #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { return DialogBox(_DS,MAKEINTRESOURCE(100),0,MainDlgProc); } #endif