Not a question, just a statement to help anyone else who might spend hours getting the Microchip PIC USB DLL to work properly with Unicode.
It expects several strings, and although these are simple PAnsiChar
, getting the right combination of DLL call convention took me ages. There are a lot of people on the 'net using Delphi (non-Unicode) with this DLL and getting away with murder.
unit UArtPic32USBDriver;
interface
uses
Windows,
SysUtils,
UArtGeneralHwDefs;
type
EArtPic32Usb = class( EArtGeneralHw );
function Pic32Usb_GetDllVersion : integer;
// Returns a number representing the DLL version.
function Pic32Usb_GetDeviceCount( const AVendorProductID : string ) : integer;
// Returns the number of devices with this vendor ID
function Pic32Usb_Open(
AInstance : DWORD;
const AVendorProductID, AEndpointID : string;
ADirectionCode : integer;
ARaise : boolean ) : THANDLE;
// Opens an endpoint. Can raise an exception if no valid handle is returned.
procedure Pic32Usb_Close( AHandle : THandle );
// Closes the device
function Pic32Usb_Write(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a write using this handle. Returns the number of bytes written
function Pic32Usb_Read(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a Read using this handle. Returns the number of bytes read
const
MP_WRITE = 0;
MP_READ = 1;
implementation
var
_MPUSBGetDLLVersion : function () :DWORD; cdecl stdcall;
// Number of vid & pid matching USB Devices
_MPUSBGetDeviceCount : function( pVID_PID : PAnsiChar ) : DWORD; cdecl;
_MPUSBOpen : function ( instance : DWORD;
pVID_PID : PAnsiChar;
pEP : PAnsiChar;
dwDir : DWORD;
dwReserved : DWORD ) : THANDLE; cdecl;
_MPUSBClose : function ( handle :THANDLE ) : DWORD; cdecl;
_MPUSBRead : function ( handle : THANDLE;
pData : pointer;
dwLen : DWORD;
var pLength : DWORD;
dwMilliseconds : DWORD ) : DWORD; cdecl;
_MPUSBReadInt : function ( handle : THANDLE;
var pData : pointer;
dwLen : DWORD;
var pLength : PDWORD;
dwMilliseconds : DWORD ) : DWORD; cdecl;
_MPUSBWrite : function ( handle : THANDLE;
pData : pointer;
dwLen : DWORD;
var pLength : DWORD;
dwMilliseconds : DWORD ) : DWORD; cdecl;
UsbDllHandle : THandle = 0;
const
MillisecondPollingInterval = 100; //Represents 1 ms is hardware
CharBufSize = 64;
type
TAnsiCharBuf64 = array[0..CharBufSize-1] of AnsiChar;
function LoadDLL : THandle;
var
S : string;
begin
S := 'mpusbapi.dll';
UsbDllHandle := LoadLibrary( PChar(S) );
If UsbDllHandle = 0 then
Raise EArtPic32Usb.CreateFmt(
'The usb library is required but cannot be loaded. Check that it is installed. (%s)',
[S]
);
@_MPUSBGetDLLVersion := GetProcAddress(UsbDllHandle,'_MPUSBGetDLLVersion');
Assert(@_MPUSBGetDLLVersion <> nil);
@_MPUSBGetDeviceCount := GetProcAddress(UsbDllHandle,'_MPUSBGetDeviceCount');
Assert(@_MPUSBGetDeviceCount <> nil);
@_MPUSBOpen := GetProcAddress(UsbDllHandle,'_MPUSBOpen');
Assert(@_MPUSBOpen <> nil);
@_MPUSBClose := GetProcAddress(UsbDllHandle,'_MPUSBClose');
Assert(@_MPUSBClose <> nil);
@_MPUSBRead := GetProcAddress(UsbDllHandle,'_MPUSBRead');
Assert(@_MPUSBRead <> nil);
@_MPUSBReadInt := GetProcAddress(UsbDllHandle,'_MPUSBReadInt');
Assert(@_MPUSBReadInt <> nil);
@_MPUSBWrite := GetProcAddress(UsbDllHandle,'_MPUSBWrite');
Assert(@_MPUSBWrite <> nil);
Result := UsbDllHandle;
end;
procedure NeedDLL;
begin
If UsbDllHandle = 0 then
LoadDll;
end;
function Pic32Usb_GetDllVersion : integer;
// Returns a number representing the DLL version.
begin
NeedDLL;
Result := _MPUSBGetDLLVersion();
end;
function Pic32Usb_GetDeviceCount( const AVendorProductID : string ) : integer;
// Returns the number of devices with this vendor ID
var
bufVendorProductID : TAnsiCharBuf64;
begin
NeedDLL;
StrPCopy( bufVendorProductID, AnsiString(AVendorProductID) );
Result := _MPUSBGetDeviceCount( @bufVendorProductID );
end;
function Pic32Usb_Open(
AInstance : DWORD;
const AVendorProductID, AEndpointID : string;
ADirectionCode : integer;
ARaise : boolean ) : THANDLE;
// Opens an endpoint. Can raise an exception if no valid handle is returned.
var
bufVendorProductID, bufEndpointID : TAnsiCharBuf64;
begin
NeedDLL;
StrPCopy( bufVendorProductID, AnsiString(AVendorProductID) );
StrPCopy( bufEndpointID, AnsiString(AEndpointID) );
Result := _MPUSBOpen(
AInstance,
@bufVendorProductID,
@bufEndpointID,
DWORD(ADirectionCode),
0 );
if Result = 0 then
If ARaise then
Raise EArtPic32Usb.CreateFmt(
'Unable to open USB device "%s", endpoint "%s"', [AVendorProductID, AEndpointID]);
end;
procedure Pic32Usb_Close( AHandle : THandle );
begin
If UsbDllHandle <> 0 then
_MPUSBClose( AHandle );
end;
function Pic32Usb_Write(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a write using this handle. Returns the number of bytes written
var
I : integer;
begin
I := _MPUSBWrite(
AHandle,
ABufferPtr,
DWORD( ALengthBytes ),
Result,
MillisecondPollingInterval );
if I <> 1 then
Raise EArtPic32Usb.CreateFmt( 'Error performing USB write', []);
end;
function Pic32Usb_Read(
AHandle : THANDLE;
ABufferPtr : pointer;
ALengthBytes : integer ) : DWORD;
// Performs a Read using this handle. Returns the number of bytes read
var
I : integer;
begin
I := _MPUSBRead(
AHandle,
ABufferPtr,
DWORD( ALengthBytes ),
Result,
MillisecondPollingInterval );
if I <> 1 then
Raise EArtPic32Usb.CreateFmt( 'Error performing USB read', []);
end;
initialization
finalization
If UsbDllHandle <> 0 then
FreeLibrary(UsbDllHandle)
end.