Quelltext /~heha/mb-iwp/HBM/usbhbm.zip/spider8direkt/spider8direkt.cpp

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