Source file: /~heha/hs/dlo/DLO_DeluxeUSB.zip/plugin-src/DLO_DeluxeUSB.c

/* Discolitez plugin, for controlling 32 channels via
 * DeluxeUSB device containing ATtiny25 and 4 74HC595
 * See schematic and firmware for this adapter!
 * Alternatively useable for DeluxeUSBmux circuitry
 * and other firmware-compatible output devices.
 *
 * This plugin uses the first DeluxeUSB adapter found
 * if zero-based number is not given by DLL file name suffix.
 */

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <shlwapi.h>
#include <setupapi.h>
#include <hidsdi.h>
#include <hidpi.h>

// Opens the n'th (zero-based) HID device that has VID=16C0, PID=05DF,
// and contains L"DeluxeUSB" somewhere in its Device Name string
// Use CloseHandle() to free the handle returned.
// Returns 0 when failing.
static HANDLE OpenUsbHid(int n) {
 HANDLE h=0;
 DWORD i;
 HDEVINFO devs;
 GUID hidGuid;		// GUID for HID driver

 HidD_GetHidGuid(&hidGuid);
 devs = SetupDiGetClassDevs(&hidGuid, NULL, 0, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
 if (devs==INVALID_HANDLE_VALUE) return h;

 for (i=0;;i++) {
  DWORD size = 0;
  PSP_DEVICE_INTERFACE_DETAIL_DATA interface_detail;
  union{
   struct{
    SP_DEVICE_INTERFACE_DATA devinterface;
    SP_DEVINFO_DATA devinfo;
   };
   HIDD_ATTRIBUTES deviceAttributes;
   WCHAR productName[32];
  }s;	// some shared buffers not used the same time (does the optimizer see that?)

  if (h) CloseHandle(h), h=0;
  s.devinterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  if (!SetupDiEnumDeviceInterfaces(devs, 0, &hidGuid, i, &s.devinterface)) break;
	// See how large a buffer we require for the device interface details
  SetupDiGetDeviceInterfaceDetail(devs, &s.devinterface, NULL, 0, &size, 0);
  s.devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
  interface_detail = LocalAlloc(LPTR,size);
  if (!interface_detail) continue;
  interface_detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  s.devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
  if (!SetupDiGetDeviceInterfaceDetail(devs, &s.devinterface, interface_detail, size, 0, &s.devinfo)) {
   LocalFree(interface_detail);	// ignore this entry in case of error
   continue;
  }
  h = CreateFile(interface_detail->DevicePath, GENERIC_READ|GENERIC_WRITE,
    FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  LocalFree(interface_detail);
  if (h == INVALID_HANDLE_VALUE) h = 0;
  if (!h) continue;
  if (!HidD_GetAttributes(h, &s.deviceAttributes)) continue;
  if (*(DWORD*)&s.deviceAttributes.VendorID != 0x05DF16C0) continue;	// not mine *)
  if (!HidD_GetProductString(h, s.productName, sizeof(s.productName))) continue;
  if (!StrStrW(s.productName,L"DeluxeUSB")) continue;	// not mine
  if (!n) break;	// found my device
  n--;			// iterate to my next device
 }
 SetupDiDestroyDeviceInfoList(devs);
 return h;
}

static HANDLE usbHandle;// from OpenUsbHid()
static DWORD PortState;	// current state of 32 LEDs
static int DevNum;	// zero-based device number
static UINT TimerId;	// from timeSetEvent()
static HINSTANCE hInst;	// the DLL's instance handle

// Sets the 32 LED states to given new state
static void OutPortState(DWORD State) {
 if (usbHandle) {
  BYTE report[5];
  report[0] = 2;		// report ID
  *(DWORD*)(report+1) = State;	// report data *)
  HidD_SetFeature(usbHandle,report,sizeof(report));
 }
} // *) The Intel architecture permits unaligned access

// The configuration dialog is merely an about box
// that shows the current state of USB-HID connection.
static BOOL CALLBACK ConfigDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
 switch (Msg) {
  case WM_INITDIALOG: {
// Show current state of DeluxeUSB found
   CheckDlgButton(Wnd,11,(UINT)usbHandle);
  }return TRUE;

  case WM_COMMAND: switch (LOWORD(wParam)) {
   case 1:
   case 2: EndDialog(Wnd,wParam); break;
   case 10: {	// re-open the DeluxeUSB (in case of some disconnection meanwhile)
    if (usbHandle) CloseHandle(usbHandle);
    usbHandle=OpenUsbHid(DevNum);
    CheckDlgButton(Wnd,11,(UINT)usbHandle);
   }break;
  }break;
 }
 return FALSE;
}

// Let a timer procedure actualize the output,
// reduce load due to too many kernel<->user mode transitions
static void CALLBACK TimerProc(UINT TimerId, UINT uMsg, DWORD dwUser,
  DWORD dw1, DWORD dw2) {
 static DWORD NewState;
 if (NewState!=PortState) OutPortState(NewState=PortState);
}

/**********************
 * exported functions *
 **********************/
BYTE _declspec(dllexport) _cdecl DLO_getnch(void) {
 return 32;
}

LPSTR _declspec(dllexport) _cdecl DLO_getname(void) {
 if (DevNum) {
  static char buf[32];
  wnsprintf(buf,sizeof(buf),"DeluxeUSB device #%d",DevNum);
  return buf;
 }
 return "DeluxeUSB device";
}

void _declspec(dllexport) _cdecl DLO_datain(BYTE ch, BYTE val) {
 DWORD mask = 1<<(ch-1);
 if (val) {
  if (PortState&mask) return;
 }else{
  if (~PortState&mask) return;
 }
 PortState ^= mask;	// The timer procedure will output this value later
}

void _declspec(dllexport) _cdecl DLO_init(void) {
 usbHandle=OpenUsbHid(DevNum);
 OutPortState(0);	// At startup, switch all LEDs off
 timeBeginPeriod(10);
 TimerId = timeSetEvent(10,10,TimerProc,0,TIME_PERIODIC);
}

void _declspec(dllexport) _cdecl DLO_done(void) {
 timeKillEvent(TimerId);
 timeEndPeriod(10);
 if (usbHandle) CloseHandle(usbHandle);
 usbHandle = 0;
}

void _declspec(dllexport) _cdecl DLO_about(void) {
 DialogBox(hInst,MAKEINTRESOURCE(100),0,ConfigDlgProc);
}

/********************
 * main entry point *
 ********************/
void CALLBACK _DllMainCRTStartup(HINSTANCE hInstDll,DWORD fdwReason,LPVOID lpReserved) {
 if (fdwReason==DLL_PROCESS_ATTACH) {
  char DllName[MAX_PATH], *p;
  hInst = hInstDll;	// Where the (dialog) resource comes from - and the file name
  if (GetModuleFileName(hInstDll,DllName,sizeof(DllName))
  && (p=StrChr(PathFindFileName(DllName),' ')))
    DevNum = StrToInt(p);
  DisableThreadLibraryCalls(hInstDll);	// returns TRUE to continue DLL loading
 }
}
Detected encoding: ASCII (7 bit)2