/* Mit dieser DLL (4 kB) kann man direkt mit einem am USB angeschlossenen Spider8 „reden“
* ohne das Rudel an DLLs aus dem Spider32-Verzeichnis nutzen zu müssen; ersetzt:
* Spider32.dll 111 kB
* intfac32.dll 86 kB
* interlnk.dll 19 kB
* Papo32.dll 41 kB
* Summe 251 kB
* Außerdem kann man hiermit mit mehreren Spider8 reden,
* wenn diese mit separaten USB-Adaptern angeschlossen sind.
* (Diese arbeiten dann allerdings nicht synchron.)
* Henrik Haftmann, TU Chemnitz, 141111
*/
#include <Windows.h>
#include <SetupAPI.h>
#define T(x) TEXT(x)
struct S8H{
HANDLE h,w,r;
OVERLAPPED o;
};
static const GUID spider8usb = {0x1B447280,0x1A9B,0x11D3,0xAD,0xCA,0x44,0x45,0x53,0x54,0x00,0x00};
// Öffnet n-ten per USB angeschlossenen Spider8 (0 = erster oder einziger).
// Der zurückgegebene Zeiger sollte nicht weiter analysiert werden,
// sondern dient als Eingabe für die übrigen DLL-Funktionen.
// Bei Fehler liefert diese Funktion NULL.
S8H* CALLBACK open(int n=0) {
S8H *ret=NULL;
HANDLE devs=SetupDiGetClassDevs(&spider8usb,NULL,0,DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
if (devs!=INVALID_HANDLE_VALUE) {
SP_DEVICE_INTERFACE_DATA devinterface;
devinterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (SetupDiEnumDeviceInterfaces(devs, NULL, &spider8usb, n, &devinterface)) {
struct{
SP_DEVICE_INTERFACE_DETAIL_DATA id;
TCHAR space[MAX_PATH];
}id;
id.id.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(devs,&devinterface,&id.id,sizeof(id)-2,0,0)) {
ret=(S8H*)LocalAlloc(LPTR,sizeof(S8H));
ret->h = CreateFile(id.id.DevicePath,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
LPTSTR e = id.id.DevicePath+lstrlen(id.id.DevicePath);
lstrcpy(e,T("\\1")); // Der Treiber ist so dämlich (bzw. universell) konstruiert
ret->w = CreateFile(id.id.DevicePath,GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
lstrcpy(e,T("\\0")); // Die intfac32.dll setzt hier "\\PIPE00" dran, usbhbm.sys interessiert sich aber nur für die letzten Ziffern
ret->r = CreateFile(id.id.DevicePath,GENERIC_READ,0,0,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
ret->o.hEvent = CreateEvent(0,0,0,0);
}
}
SetupDiDestroyDeviceInfoList(devs);
}
return ret;
} // funktioniert.
// Senden und Empfangen.
// str: Sendedaten, sollte mit '\n' abgeschlossen sein
// strsize = -1: Die Länge der Sendedaten ergibt sich aus der Nullterminierung.
// strsize = 0: Nichts wird gesendet
// buf: Empfangsdatenpuffer
// bufsize: positiv für Binärdatenempfang (es werden exakt <bufsize> Bytes gelesen)
// negativ für Text-Empfang (es werden maximal <-bufsize> Zeichen gelesen und bei "\r\n" abgebrochen)
// 0: Nichts wird empfangen
// Returnwert: Gelesene Zeichen, einschließlich dem üblicherweise abschließendem "\r\n"
// -2 für Fehler beim Senden, -1 für Fehler beim Empfang
// Timeout = 500 ms (fest) für jede Transaktion)
int CALLBACK sendrecv(S8H *h, const char*str, int strsize, char*buf, int bufsize) {
if (strsize<0) strsize=lstrlenA(str);
bool end_crlf=false;
if (bufsize<0) {bufsize=-bufsize; end_crlf=true;}
DWORD xfer;
int i=0;
while (i!=strsize) {
if (!WriteFile(h->w,str+i,strsize-i,&xfer,&h->o) // womöglich in USB-Paketstückelung (64 Byte)
&& (GetLastError()!=ERROR_IO_PENDING
|| WaitForSingleObject(h->o.hEvent,500) // max. ½ Sekunde auf USB-BulkOut warten
|| !GetOverlappedResult(h->w,&h->o,&xfer,FALSE))) {
CancelIo(h->w);
return -2;
}
i+=xfer;
}
i=0;
while (i!=bufsize) {
if (!ReadFile(h->r,buf+i,bufsize-i,&xfer,&h->o) // womöglich in USB-Paketstückelung (64 Byte)
&& (GetLastError()!=ERROR_IO_PENDING
|| WaitForSingleObject(h->o.hEvent,500) // max. ½ Sekunde auf Antwort warten
|| !GetOverlappedResult(h->r,&h->o,&xfer,FALSE))) {
CancelIo(h->r);
return -1;
}
i+=xfer;
if (end_crlf && i>=2 && buf[i-2]=='\r' && buf[i-1]=='\n') break;
}
return i;
} // funktioniert GENAU SO!
void CALLBACK flush(S8H *h) {
char buf[256];
DWORD br;
while (ReadFile(h->r,buf,sizeof buf,&br,&h->o)); // Lesen bis Ende, blockiert nicht
if (GetLastError()==ERROR_IO_PENDING) CancelIo(h->r); // angeschubste Transaktion abbrechen
}
void CALLBACK close(S8H *h) {
CloseHandle(h->r);
CloseHandle(h->w);
CloseHandle(h->h);
CloseHandle(h->o.hEvent);
LocalFree(h);
}
// Einfache Testfunktion, Aufruf durch "rundll32 spider8direkt,Test"
// Es leuchtet die gelbe Transfer-LED kurz auf,
// und die rote Error-LED geht aus falls diese an war.
// Im Normalfall zeigt sich ein Meldungsfenster mit dem Fehlerkode, zumeist "0".
// Bei sonstigem Fehler (keine USB-Verbindung) passiert nichts.
//
// Mittels "rundll32 spider8direkt,Test <kommando>" kann man auch alles andere erfragen/setzen.
// Siehe spider8.hlp oder spider8.chm.
// Allerdings kommt bei "OMB?" Quatsch heraus,
// und bei zufälligem CRLF im Datenstrom wird vorzeitig abgebrochen.
void CALLBACK TestA(HWND wnd,HINSTANCE,char*cmdline,int) {
S8H *h=open();
if (h) {
flush(h); // löscht noch anstehende Eingabedaten
char s[256];
if (lstrlenA(cmdline)) lstrcpynA(s,cmdline,sizeof s-1);
else lstrcpyA(s,"EST?");
lstrcatA(s,"\n");
int len=sendrecv(h,s,-1,s,-(int)(sizeof s-1)); // Senden und Empfangen im Textmodus
if (len>=0) {
s[len]=0;
MessageBoxA(wnd,s,"OK",0);
}
close(h);
}
}
| Vorgefundene Kodierung: UTF-8 | 0
|