Nota: En este post se hace referencia a articulos en las paginas de
Club Delphi:
USB-HID(micropascal, componente hid de la JEDI), USB-Bulk(CCS-mpusbapi.dll v1.0.0 y v1.1.0).
Como sabemos la WinUSB está habilitada en Windows XP, Windows Vista, Windows Server 2008 y Windows 7.
Pero solo viene incluido en el sistema desde Windows Vista; en XP es necesario instalarla.
Tanto la WinUSB y la mpusbapi.dll v1.1.0.0 de Microchip son compatibles con Windows Vista.
Recordemos que la norma USB dispone de 4 tipos para transmisión de datos:
·Control
·Bulk
·Interrupt
·Isochronous
Y varias clases de dispositivos posibles:
·USB audio device
·USB Communications device
·USB human interface device(HID)
·USB printer device
·USB massstorage device
·USB hub device
·USB smart card reader device
·USB video device
·USB wireless device
·Etc.
Pero la WinUSB no soporta el tipo de transmisión Isochronous.
Cuando instalamos la WinUSB se crea el archivo winusb.sys en el directorio del sitema, que es en realidad el driver con el que nuestra aplicación se comunicara para manejar nuestro dispositivo USB; para instalarla son necesarios los siguientes archivos:
1. WinUSBCoInstaller.dll
2. WdfCoInstaller01007.dll
3. Un .inf para instalar la winusb.sys.
Estos archivos deben de coincidir con la arquitectura de la CPU: x86 o x64; y vienen incluidas con la Windows Driver Kid (WDK).
La documentación basica de como realizar todo el proceso para crear el software se puede encontrar en :
“How to Use WinUSB to Communicate with a USB Device.pdf”, la cual tambien adjunto en el archivo del proyecto.
La documentación sobre las funciones de la WinUSB, la podemos encontrar en la ayuda de: Visual Studio, Rad Studio 2009, y en la propia documentación de la
Windows Driver Kid (WDK), Solo bastara buscarlas como: “WinUSB User-Mode Client Support Routines”.
La WinUSB consta de 20 funciones, de las cuales muchas solicitan o devuelven parámetros estructurados (record).
A diferencia de la dll de Microchip, esta no posee una función que directamente devuelva el handle al dispositivo USB, la función de la WinUSB: WinUSB_Initialize(), requiere que se le pase el manejador al dispositivo…es decir esto se tiene que hacer a mano; a diferencia de la dll de Microchip,
que para inicializarla solo requería pasarle el VID and PID y nos retornaba el handle.
Delphi :
El handle requerido por la WinUSB_Initialize () lo podemos conseguir pasando el path del dispositivo (si revisamos este lo podemos encontrar en el registro de Windows), a la conocida función CreateFile(); hasta aquí todo bien, pero para conseguir este path es necesario hacer uso de varias funciones de la SetupApi.dll, la cual no está importada en Delphi (lo estará en D2009?).
Asi que nos queda 2 alternativas la importamos nosotros mismos o hacemos uso de las fantásticas utilidades del
PROJECT JEDI.
La JEDI API Library, (descargar "scapi - Setup & Config Manager API") tiene importadas todas estas funciones (cosa que podríamos hacer pero tal vez no tan eficientemente o podemos inventar nuevamente la rueda),
para usar esta librería de unidades solo tenemos como es costumbre que agregarla a Environment Options\Library\Library path.
Otro detalle es que algunas de las funciones que usamos de la SetupApi necesitan un GUID para la interface del dispositivo (GUID_DEVINTERFACE),
este valor también deberá ser incluido en el archivo INF (MyWinUSB.inf); la forma como el driver winusb.sys se reconoce como controlador de
nuestro dispositivo USB.
Este GUID lo podemos generar haciendo Ctrl+Shift+G (ó Ctrl+Mayus+G) en el editor de Delphi.
El projecto consta de 3 unidades: el program en si, la importacion de las funciones de la WinUSB.dll y la unidad en las que se declaran los parametros estructurados para las funciones de la dll.
.
.
.
Const
//La interface GUID ubicada en al seccion [Dev_AddReg] del .inf
GUID_DEVINTERFACE: TGUID = '{9FD6FF49-05EC-49C4-9B78-371937D1E315}';
//constante para la funcion WinUsb_QueryDeviceInformation - referirse a la doc de la WinUSB
DEVICE_SPEED = $001;
.
.
.
//SetupApi unidad de la JEDI API Library
uses WINUSBDll, TypesDll, SetupApi;
.
.
.
//casi todas las funciones aqui son de la SetupApi
//documentacion al respecto en la ayuda de: visual studio,
//C++/Delphi 2009, Windows Driver Kit(WDK)
function TForm1.GetDevicePath: THandle;
var
BytesReturned : DWORD;
LPGUID : TGUID;
DeviceInfo : HDEVINFO;
DeviceInterfaceData : TSPDeviceInterfaceData;
DetailData : PSPDeviceInterfaceDetailData;
begin
LPGUID := GUID_DEVINTERFACE;
DetailData:= nil;
GetDevicePath:= INVALID_HANDLE_VALUE;
//SetupDiGetClassDevs : obtiene un handle hacia la informacion de la device
DeviceInfo:=SetupDiGetClassDevs(@LPGUID, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE);
if not(DeviceInfo = Pointer(INVALID_HANDLE_VALUE)) then
begin
//inicializa la estructura TSPDeviceInterfaceData
DeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData);
//SetupDiEnumDeviceInterfaces : enumera todas las interfaces de las devices
if SetupDiEnumDeviceInterfaces(DeviceInfo, nil, LPGUID, 0, DeviceInterfaceData) then
begin
//SetupDiGetDeviceInterfaceDetail : obtiene detalles de la informacion de la interface
//de nuestra deviceestos datos son almacenados en la estructura TSPDeviceInterfaceDetailData
if not SetupDiGetDeviceInterfaceDetail(DeviceInfo, @DeviceInterfaceData, nil, 0,
BytesReturned, nil) then
begin
DetailData := AllocMem(BytesReturned);
if DetailData = Pointer(INVALID_HANDLE_VALUE) then
begin
SetupDiDestroyDeviceInfoList(DeviceInfo);
GetDevicePath:=INVALID_HANDLE_VALUE;
end;
DetailData.cbSize:= SizeOf(TSPDeviceInterfaceDetailData);
//SetupDiGetDeviceInterfaceDetail : obtiene el tamño correcto para la estructura
//TSPDeviceInterfaceDetailData
if SetupDiGetDeviceInterfaceDetail(DeviceInfo, @DeviceInterfaceData, DetailData,
BytesReturned, BytesReturned, nil) = false then
begin
FreeMem(DetailData);
GetDevicePath:=INVALID_HANDLE_VALUE;
end;
if DetailData.DevicePath = '' then
begin
SetupDiDestroyDeviceInfoList(DeviceInfo);
FreeMem(DetailData);
end;
//obtenemos un handle para la device
GetDevicePath := CreateFile(DetailData.DevicePath, GENERIC_WRITE or GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0 );
FreeMem(DetailData);
end;
end;
end;
end;
Las funciones de la WinUSB nos permiten obtener abundante información sobre el descriptor en el PIC
PIC :
El código en el PIC es el mismo que usamos anteriormente compilado con el CCS C: USB_Bulk.
INF :
para detalles sobre el .INF debemos referirnos al apartado "How to Install WinUsb.sys as a Function Driver" del documento
“How to Use WinUSB to Communicate with a USB Device.pdf” y al capitulo 9 del libro
"Usb Complete - Everything You Need To Develop Custom Usb Peripherals" de Jan Alelxon
En el archivo MyWinUSB.inf son importantes los dos GUID que se deben incluir
1. ClassGuid: este valor puede ser eligido de entre los definidos en C:\WinDDK\6001.18002\inc\api\ devguid.h
(carpeta de instalscion de la WDK); pero se acostumbra usar uno propio.
2. DeviceInterfaceGUIDs en la sección [Dev_AddReg]:
este GUID es el mismo que está incluido en el código Delphi, el GUID para la interface de nuestro dispositivo USB.
Podemos generar un GUID haciendo Ctrl+Shift+G (ó Ctrl+Mayus+G) en el editor de Delphi.
Algo rapido:
1. grabar el .hex en el PIC
2. Al conectar el cable te pedira el driver, elije la carpeta "\My WinUSB with Delphi\PC\Driver".
3. Listo ejecuta MyWinUSB.exe
el proyecto completo se puede descargar de:
My WinUSB con Delphi.rar