Sourcecode k8061.dll

Since the k8061.dll is a building block for greater machines, I was wondering if there is a source code for the k8061.dll file or the drivers. I think it’s then possible to finetune some of the properties of the card, like event driven reaction for the input channels or the buggy results out of the connected() and powergood() functions.

p.s. I wanted to sent an email but I couldn’t find one for these specific computer related questions.

I hope its possible!
Thanks in advance

If you succeed to modify this code to be event driven, please post the source (and some example) to this forum!
Also any other suggestions to improve the code are welcome.
Here is the source code of the original DLL.

K8061D.DPR

[code]library K8061;

{ Important note about DLL memory management: ShareMem must be the
first unit in your library’s USES clause AND your project’s (select
View-Project Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL–even those that
are nested in records and classes. ShareMem is the interface unit to
the DELPHIMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using DELPHIMM.DLL, pass string information
using PChar or ShortString parameters. }

uses
SysUtils,
Classes,
K8061D in ‘K8061D.pas’;

exports
OpenDevice,
CloseDevices,
ReadAnalogChannel,
ReadAllAnalog,
OutputAnalogChannel,
OutputAllAnalog,
ClearAnalogChannel,
ClearAllAnalog,
SetAnalogChannel,
SetAllAnalog,
OutputAllDigital,
ClearDigitalChannel,
ClearAllDigital,
SetDigitalChannel,
SetAllDigital,
ReadDigitalChannel,
OutputPWM,
ReadAllDigital,
ReadCounters,
ReadVersion,
ResetCounters,
PowerGood,
Connected,
ReadBackDigitalOut,
ReadBackAnalogOut,
ReadBackPWMOut;

end.[/code]
K8061D.PAS

[code]unit K8061D;

interface
uses
Windows, SysUtils;

function OpenDevice: Longint ; stdcall;
procedure CloseDevices; stdcall;
function ReadAnalogChannel(CardNumber: Longint; Channel: Longint):Longint; stdcall;
procedure ReadAllAnalog(CardNumber: Longint; Buffer: Pointer); stdcall;
procedure OutputAnalogChannel(CardNumber: Longint; Channel: Longint; Data: Longint); stdcall;
procedure OutputAllAnalog(CardNumber: Longint; Buffer: Pointer); stdcall;
procedure ClearAnalogChannel(CardNumber: Longint; Channel: Longint); stdcall;
procedure ClearAllAnalog(CardNumber: Longint); stdcall;
procedure SetAnalogChannel(CardNumber: Longint; Channel: Longint); stdcall;
procedure SetAllAnalog(CardNumber: Longint); stdcall;
procedure OutputAllDigital(CardNumber: Longint; Data: Longint); stdcall;
procedure ClearDigitalChannel(CardNumber: Longint; Channel: Longint); stdcall;
procedure ClearAllDigital(CardNumber: Longint); stdcall;
procedure SetDigitalChannel(CardNumber: Longint; Channel: Longint); stdcall;
procedure SetAllDigital(CardNumber: Longint); stdcall;
function ReadDigitalChannel(CardNumber: Longint; Channel: Longint): Boolean; stdcall;
function ReadAllDigital(CardNumber: Longint): Longint; stdcall;
procedure OutputPWM(CardNumber: Longint; Data: Longint); stdcall;
procedure ReadCounters(CardNumber: Longint; Buffer: Pointer); stdcall;
procedure ResetCounters(CardNumber: Longint); stdcall;
procedure ReadVersion(CardNumber: Longint; Buffer: Pointer); stdcall;
procedure CheckInvalidHandle(CardNumber: Longint);
procedure OutIn(CardNumber:Longint; Tx:DWORD; Rx:DWORD);
function PowerGood(CardNumber: Longint): Boolean; stdcall;
function Connected(CardNumber: Longint): Boolean; stdcall;

function ReadBackDigitalOut(CardNumber: Longint):Longint; stdcall;
procedure ReadBackAnalogOut(CardNumber: Longint; Buffer: Pointer); stdcall;
function ReadBackPWMOut(CardNumber: Longint):Longint; stdcall;

implementation
var
OutPipe: array[0…7] of THandle;
InPipe: array[0…7] of THandle;
open: array[0…7] of boolean;
send_buf:array[0…50] of byte;
receive_buf:array[0…50] of byte;
i:integer;
instance:DWORD;

//function _MPUSBGetDLLVersion:Dword; cdecl; external ‘mpusbapi.dll’;
function _MPUSBGetDeviceCount(pVID_PID:PCHAR):Dword; cdecl; external ‘mpusbapi.dll’
function _MPUSBOpen(instance:DWORD; pVID_PID:PCHAR; pEP:PCHAR; dwDir:DWORD; dwReserved:DWORD):THandle; cdecl; external ‘mpusbapi.dll’;
function _MPUSBWrite(handle:THandle; pData:Pointer; dwLen:DWORD; pLength:Pointer; dwMilliseconds:DWORD):DWord; cdecl; external ‘mpusbapi.dll’;
function _MPUSBRead(handle:THandle; pData:Pointer; dwLen:DWORD; pLength:Pointer; dwMilliseconds:DWORD):DWord; cdecl; external ‘mpusbapi.dll’;
function _MPUSBClose(handle:THANDLE):DWORD; cdecl;external ‘mpusbapi.dll’;

procedure CheckInvalidHandle(CardNumber: Longint);
begin
if(GetLastError=ERROR_INVALID_HANDLE) then
begin
// Most likely cause of the error is the board was disconnected.
_MPUSBClose(OutPipe[CardNumber]);
_MPUSBClose(InPipe[CardNumber]);
InPipe[CardNumber]:=INVALID_HANDLE_VALUE;
OutPipe[CardNumber]:=INVALID_HANDLE_VALUE;
open[CardNumber]:=false;
end;
//else
//ShowMessage(‘Error Code :’+inttostr(GetLastError()));
end;

function OpenDevice: Longint; stdcall;
var OutPipe_tmp,InPipe_tmp:THandle;
SentDataLength,ReceiveLength:DWORD ;
tmp,i:byte;
begin
//MPUSBOpen(selection,vid_pid,out_pipe,MP_WRITE,0);
if (_MPUSBGetDeviceCount(pchar(‘vid_10cf&pid_8061’)))=0 then
begin
result:=-2;
exit
end;
OutPipe_tmp:=_MPUSBOpen(instance,pchar(‘vid_10cf&pid_8061’),pchar(’\MCHP_EP1’),0,0);
InPipe_tmp:=_MPUSBOpen(instance,pchar(‘vid_10cf&pid_8061’),pchar(’\MCHP_EP1’),1,0);
if (OutPipe_tmp<>INVALID_HANDLE_VALUE) and (InPipe_tmp<>INVALID_HANDLE_VALUE) then
begin
send_buf[0] := 12; //JUMPERS
_MPUSBWrite(OutPipe_tmp,@send_buf,1,@SentDataLength,1000);
_MPUSBRead(InPipe_tmp,@receive_buf,2,@ReceiveLength,1000);
tmp:=receive_buf[1];
open[tmp]:=true;
OutPipe[tmp]:=OutPipe_tmp;
InPipe[tmp]:=InPipe_tmp;
inc(instance);
result:=tmp;
end
else
begin
result:=-1;
end;
end;

procedure CloseDevices; stdcall;
var i:integer;
begin
for i:=0 to 7 do
begin
if open[i] then _MPUSBClose(OutPipe[i]);
if open[i] then _MPUSBClose(InPipe[i]);
open[i]:=false;
InPipe[i]:=INVALID_HANDLE_VALUE;
OutPipe[i]:=INVALID_HANDLE_VALUE;
end;
end;

function ReadAnalogChannel(CardNumber: Longint; Channel: Longint):Longint; stdcall;
begin
send_buf[0] := 0; //READ_ANALOG_CH
if Channel>8 then Channel:=8;
if Channel<1 then Channel:=1;
send_buf[1] := byte(Channel-1);
OutIn(CardNumber,2,4);
result:=receive_buf[2]+256*receive_buf[3];
end;

procedure ReadAllAnalog(CardNumber: Longint; Buffer: Pointer ); stdcall;
var p:^longint;
i,n:integer;
begin
p:=Buffer;
send_buf[0] := 1; // READ_ALL_ANALOG
OutIn(CardNumber,1,17);
for i:= 0 to 7 do
begin
n:=receive_buf[i*2+1]+256*receive_buf[i*2+2];
p^:=n;
inc§;
end;
end;

procedure OutputAnalogChannel(CardNumber: Longint; Channel: Longint; Data: Longint); stdcall;
begin
send_buf[0] := 2; // OUT_ANALOG_CH
if Channel>8 then Channel:=8;
if Channel<1 then Channel:=1;
send_buf[1] := Channel-1; // ch
send_buf[2] := Data; // data
OutIn(CardNumber,3,4);
end;

procedure OutputAllAnalog(CardNumber: Longint; Buffer: Pointer); stdcall;
var i:integer;
p:^longint;
begin
p:=Buffer;
send_buf[0] := 3; // OUT_ALL_ANALOG
for i:=1 to 8 do
begin
send_buf[i] := p^;
inc§;
end;
OutIn(CardNumber,9,2);
end;

procedure ClearAnalogChannel(CardNumber: Longint; Channel: Longint); stdcall;
begin
send_buf[0] := 2; // OUT_ANALOG_CH
send_buf[1] := Channel-1; // ch
send_buf[2] := 0; // data
OutIn(CardNumber,3,4);
end;

procedure ClearAllAnalog(CardNumber: Longint); stdcall;
var i:integer;
begin
send_buf[0] := 3; // OUT_ALL_ANALOG
for i:=1 to 8 do
begin
send_buf[i] := 0;
end;
OutIn(CardNumber,9,2);
end;

procedure SetAnalogChannel(CardNumber: Longint; Channel: Longint); stdcall;
begin
send_buf[0] := 2; // OUT_ANALOG_CH
send_buf[1] := Channel-1; // ch
send_buf[2] := 255; // data
OutIn(CardNumber,3,4);
end;

procedure SetAllAnalog(CardNumber: Longint); stdcall;
var i:integer;
begin
send_buf[0] := 3; // OUT_ALL_ANALOG
for i:=1 to 8 do
begin
send_buf[i] := 255;
end;
OutIn(CardNumber,9,2);
end;

procedure OutputPWM(CardNumber: Longint; Data: Longint); stdcall;
var k:DWORD ;
hi,lo:byte;
i:integer;
begin
k:=Data;
asm
mov eax,k
and al,03h
mov lo,al
mov eax,k
shr eax,2
mov hi,al
end;
send_buf[0] := 4; //OUT_PWM
send_buf[1] := lo;
send_buf[2] := hi;
OutIn(CardNumber,3,4);
end;

function ReadAllDigital(CardNumber: Longint): Longint; stdcall;
var i:integer;
begin
send_buf[0] := 5; //READ_DIGITAL_BYTE
OutIn(CardNumber,1,2);
result:=receive_buf[1];
end;

procedure OutputAllDigital(CardNumber: Longint; Data: Longint); stdcall;
begin
send_buf[0] := 6; //OUT_DIGITAL_BYTE
send_buf[1] := Data;
OutIn(CardNumber,2,3);
end;

function ReadDigitalChannel(CardNumber: Longint; Channel: Longint): Boolean; stdcall;
var b:byte;
begin
send_buf[0] := 5; //READ_DIGITAL_BYTE
OutIn(CardNumber,1,2);
b:=1;
b:=b shl (Channel-1);
result:=((receive_buf[1] and b)>0);
end;

procedure ClearDigitalChannel(CardNumber: Longint; Channel: Longint); stdcall;
var k:longint;
begin
k:=255-round(Exp((Channel-1)*ln(2)));
send_buf[0] := 7; // Clear Digital Channel
send_buf[1] := k;
OutIn(CardNumber,2,3);
end;

procedure ClearAllDigital(CardNumber: Longint); stdcall;
begin
send_buf[0] := 6; //OUT_DIGITAL_BYTE
send_buf[1] := 0;
OutIn(CardNumber,2,3);
end;

procedure SetDigitalChannel(CardNumber: Longint; Channel: Longint); stdcall;
var k:longint;
begin
k:=round(Exp((Channel-1)*ln(2)));
send_buf[0] := 8; // Set Digital Channel
send_buf[1] := k;
OutIn(CardNumber,2,3);
end;

procedure SetAllDigital(CardNumber: Longint); stdcall;
begin
send_buf[0] := 6; //OUT_DIGITAL_BYTE
send_buf[1] := 255;
OutIn(CardNumber,2,3);
end;

procedure ReadCounters(CardNumber: Longint; Buffer: Pointer ); stdcall;
var p:^longint;
i,n:integer;
begin
p:=Buffer;
send_buf[0] := 9; // READ_ERRORS
OutIn(CardNumber,1,5);
for i:= 0 to 1 do
begin
n:=receive_buf[i*2+1]+256*receive_buf[i*2+2];
p^:=n;
inc§;
end;
end;

procedure ResetCounters(CardNumber: Longint); stdcall;
begin
send_buf[0] := 10; // READ_ERRORS
OutIn(CardNumber,1,2);
end;

function PowerGood(CardNumber: Longint): boolean; stdcall;
begin
send_buf[0] := 13; // POWER_STATUS
OutIn(CardNumber,1,2);
result:=boolean(receive_buf[1]);
end;

function Connected(CardNumber: Longint): boolean; stdcall;
begin
result:=open[CardNumber];
end;

procedure ReadVersion(CardNumber: Longint; Buffer: Pointer ); stdcall;
var
p:^longint;
i,n:integer;
b:byte;
begin
p:=Buffer;
send_buf[0] := 11; // READ_VERSION
OutIn(CardNumber,1,49);
for i:= 1 to 24 do
begin
b:=receive_buf[i];
p^:=b;
inc§;
end;
p^:=ord(’ ‘);
inc§;
p^:=ord(’ ');
inc§;
for i:= 25 to 48 do
begin
b:=receive_buf[i];
p^:=b;
inc§;
end;
end;

procedure OutIn(CardNumber:Longint; Tx:DWORD; Rx:DWORD);
var SentDataLength,ReceiveLength:DWORD ;
h:DWORD ;
begin
if open[CardNumber] then h:=_MPUSBWrite(OutPipe[CardNumber],@send_buf,Tx,@SentDataLength,1000);
if h=0 then CheckInvalidHandle(CardNumber);
if open[CardNumber] then h:=_MPUSBRead(InPipe[CardNumber],@receive_buf,Rx,@ReceiveLength,1000);
if h=0 then CheckInvalidHandle(CardNumber);
end;

function ReadBackDigitalOut(CardNumber: Longint): Longint; stdcall;
var i:integer;
begin
send_buf[0] := 14; //READ_DIGITAL_OUT
OutIn(CardNumber,1,2);
result:=receive_buf[1];
end;

procedure ReadBackAnalogOut(CardNumber: Longint; Buffer: Pointer ); stdcall;
var p:^longint;
i,n:integer;
begin
p:=Buffer;
send_buf[0] := 15; // READ_ANALOG_OUT
OutIn(CardNumber,1,9);
for i:= 1 to 8 do
begin
n:=receive_buf[i];
p^:=n;
inc§;
end;
end;

function ReadBackPWMOut(CardNumber: Longint):Longint; stdcall;
begin
send_buf[0] := 16; // READ_PWM_OUT
OutIn(CardNumber,1,3);
result:=receive_buf[1]+4*receive_buf[2];
end;

initialization
for i:=0 to 7 do open[i]:=false;
instance:=0;

end.[/code]

Ok thanks, this is great. I was actually currently working on a class working with the original 2.0 version to generate events, but I ran into some problems which I can correct with this source.
The class I made is working at the moment to generate events like “powerdown, disconnect en event for de digital in channels”. It must be said that the class just works like the demo of the k8061, so every 30 msecs it scans for changes. But i does generate events, that I think is already a lot more easier to use for some people.

p.s. It does take a while to post the class, I don’t have a lot of time these days.

Btw, do you have the source code for the file ‘mpusbapi.dll’ ?
Is the source code you just posted the 2.0 version or 1.0?

Nice if you get your event-driven code working!
This source code is for version 1.0. Sorry, I do not have the source for version 2.0.

Yes, I have the source code for the file ‘mpusbapi.dll’ and you’ll have it soon too:

  • Go to www.microchip.com
  • In the ”Design” box click the ”Application Design Center”.
  • Under the text: ”Connectivity Solutions” click ”USB”.
  • Click: ”Full Speed USB Solutions” text or the picture.
  • Scroll down until you see text: ”Download Free USB Firmware now to get started with your Full-Speed USB Design:”.
  • Below it click: ” Microchip Custom Driver”.
  • Finally click: “Software Download: MCHPFSUSSB_Setup.zip”

Or simply download: en021826.zip
Extract the file MCHPFSUSB_Setup.EXE and run it.
It installs a packlage of example projects for PIC microcontroller with USB. There are also examples for the PC and the source code for the mpusbapi.dll.

The source is in the folder: C:\MCHPFSUSB\Pc\Mpusbapi\Dll\Borland_C\Source

Have fun!

Ok thanks, I hope I can implement the class in the DLL. It’s a pitty by the way that the k8061.dll is made in deplhi… maja.

Is it possible by the way to get the sourcecode for the 2.0 version? When I take some time to code something for the card I don’t want to work with the old file which probably has some bugs in it. Hope so! :smiley:

There are no bugs in the version 1.0 but the version 2.0 is made for Windows Vista.
By reading this source code you can anyhow see how the DLL communicates with the firmware of the PIC. I hope this helps you to develop a new event-driven version of it…

Ok, maybe I was a bit too enthousiastic, ‘mpusbapi.dll’ is understandable but this DLL is only made to give an easy interaction with the drivers. Understanding the drivers and firmware is quite difficult. But I was wondering, did velleman make their own firmware for the chip? Isn’t it then a small step to implement one of the multiple timers(implemented in the chip itself) to make a REAL event driven card(polling)? When I make an event driven DLL it’s just an softwarelike approach to it. I does do the job but it’s slower and has more chance to mis an input.

By the way, ís it possible to flash the firmware with your own version or do you need the chip to be in a special card?

The USB is polling system and controlled by the host (PC). I think the firmware of the PIC can’t invoke any event if the host is not “asking” for it. I think your software based approach is OK.
Yes, Velleman made own firmware for the chip. The source code and the hex file are not available.
In the folder C:\MCHPFSUSB\fw there are several firmware examples made by Microchip for the PIC.

hep.princeton.edu/~tziegler/ … usbapi.cpp

Source code for the mpusbapi dll

Also note that K8061D.dll is no longer threadsafe while mpusbapi.dll is

[quote=“VEL255”]The USB is polling system and controlled by the host (PC). I think the firmware of the PIC can’t invoke any event if the host is not “asking” for it. I think your software based approach is OK.
Yes, Velleman made own firmware for the chip. The source code and the hex file are not available.
In the folder C:\MCHPFSUSB\fw there are several firmware examples made by Microchip for the PIC.[/quote]

Well I read some of the manuals for the PICS, and I really think it should be possible… In the PIC itself you can run a loop just as I did.(kick the dog)