Using VM110N on a Mac (as opposed to a P8055)

Hi
I have been successfully using a P8055-1 module to conduct some experiments. The module is connected to a Mac running OS-X. I have written an Objective C / Xcode application that is based on the various bits of code I have found here and on the web. It opens a USB HID device directly from the application (ie no library/dll) and reads from the two ADCs and writes to the digital outputs.
But I need more speed. So I bought a PVM110N-1 module which I want to use instead with the same functionality (ie just the two ADCs and digital outputs). Unfortunately when I replace the P8055 module with the PVM110N-1 board, some of the HID calls don’t do anything.
The software finds the VM110N board okay and by hacking (reading every element repeatedly) I have worked out how to read the two ADCs. So I am halfway there. But I cannot work out how to write to the digital outputs. The card is okay itself as it works fine on a Windows 7 PC using the new DLLs. But I need to work out which cookie to use, and what values to send.
Can someone please tell me what changed with writing to the Digital Outputs between the P8055 and the PVM110N-1.
Thanks
Mike

The K8055N can work in compatibility mode with the old K8055 DLL and in the new mode with the new DLL version. You can easily put the card to the new mode.

Here the original K8055 / VM110 instructions:

The byte [0] is always 0.
The byte [1] is 1 to set the debounce time of counter 1.
The byte [1] is 2 to set the debounce time of counter 2.
The byte [1] is 3 to reset counter 1.
The byte [1] is 4 to reset counter 2.
The byte [1] is 5 to send other data to the K8055:

The byte [2] is the digital output byte.
The byte [3] is the analog channel 1 output byte.
The byte [4] is the analog channel 2 output byte.
The byte [7] is the debounce time of counter 1.
The byte [8] is the debounce time of counter 2.

Rx [0]
Rx [1] Digital input
Rx [2] Jumpers
Rx [3] AD 1
Rx [4] AD 2
Rx [5] counter 1 low byte
Rx [6] counter 1 high byte
Rx [7] counter 2 low byte
Rx [8] counter 2 high byte


Here are the K8055N / VM110N instructions:

The byte [1] is to be set 6 to put the card to new mode.

When done, the card works in the new K8055N mode with the following instructions:

The byte [0] is always 0.
The byte [1] is 11 to set the debounce time of counter 1.
The byte [1] is 12 to set the debounce time of counter 2.
The byte [1] is 13 to reset counter 1.
The byte [1] is 14 to reset counter 2.
The byte [1] is 15 to send other data to the K8055N
The byte [1] is 16 to read digital inputs.
The byte [1] is 17 to read all analog inputs.
The byte [1] is 18 to read counter 1 (32-bit).
The byte [1] is 19 to read counter 2 (32-bit).
The byte [1] is 20 to read counter 1 (16-bit).
The byte [1] is 21 to read counter 2 (16-bit).
The byte [1] is 22 to read all (analog and digital).
The byte [1] is 23 to set PWM.
The byte [1] is 24 to read back digital Out.
The byte [1] is 25 to read back analog Out.

The byte [2] is the digital output byte.
The byte [3] is the analog channel 1 output byte (PWM1).
The byte [4] is the analog channel 2 output byte (PWM2).
The byte [7] is the debounce time of counter 1.
The byte [8] is the debounce time of counter 2.

Rx [0]
Rx [1] Digital input
Rx [2] Jumpers
Rx [3] AD 1
Rx [4] AD 2
Rx [5] counter 1 low byte
Rx [6] counter 1 high byte
Rx [7] counter 2 low byte
Rx [8] counter 2 high byte

Here is the K8055N DLL source:

[size=85][code]unit K8055DM;

interface
uses
Windows, Math;

function OpenDevice(CardNumber: integer): integer ; stdcall;
function SearchDevices: integer; stdcall;
procedure CloseDevice; stdcall;
function SetCurrentDevice(CardNumber: integer): integer; stdcall;
function ReadAnalogChannel(Channel: integer):integer; stdcall;
procedure ReadAllAnalog(var Data1, Data2: integer); stdcall;
procedure OutputAnalogChannel(Channel: integer; Data: integer); stdcall;
procedure OutputAllAnalog(Data1: integer; Data2: integer); stdcall;
procedure ClearAnalogChannel(Channel: integer); stdcall;
procedure ClearAllAnalog; stdcall;
procedure SetAnalogChannel(Channel: integer); stdcall;
procedure SetAllAnalog; stdcall;
procedure WriteAllDigital(Data: integer); stdcall;
procedure ClearDigitalChannel(Channel: integer); stdcall;
procedure ClearAllDigital; stdcall;
procedure SetDigitalChannel(Channel: integer); stdcall;
procedure SetAllDigital; stdcall;
function ReadDigitalChannel(Channel: integer): Boolean; stdcall;
function ReadAllDigital: integer; stdcall;
function ReadCounter(CounterNro: integer): integer; stdcall;
function ReadCounter16(CounterNro: integer): integer; stdcall;
procedure ResetCounter(CounterNro: integer); stdcall;
procedure SetCounterDebounceTime(CounterNro, DebounceTime:integer); stdcall;
function Version: integer; stdcall;
function Connected: boolean; stdcall;
procedure ReadAll(Buffer:Pointer); stdcall;
procedure SetPWM(Channel: integer; Data: integer; Frequency: integer); stdcall;
function ReadBackDigitalOut:Longint; stdcall;
procedure ReadBackAnalogOut(Buffer: Pointer); stdcall;

procedure OutIn(CardAddress:integer; Tx:integer; Rx:integer);

var
i, CardAddress: integer;
modeNew: boolean;
open: array[0…3] of boolean;
Buf_tx:array[0…64] of byte;
Buf_rx:array[0…64] of byte;
Buf_cards:array[0…8, 0…3] of byte;
hDeviceWrite: array[0…3] of THandle;
hDeviceRead: array[0…3] of THandle;

implementation

uses findpath;

function SearchDevices: integer; stdcall;
begin
CloseDevice;
givepath;
CloseDevice;
result:=givepath;
end;

function OpenDevice(CardNumber: integer): integer ; stdcall;
begin
CloseDevice;
givepath;
CloseDevice;
givepath;
CardAddress:=CardNumber;
if open[CardNumber] then
begin
result:=CardNumber;
Buf_tx[1]:=6; //check if New version
OutIn(CardAddress,1,1);
if Buf_rx[2]>10 then
begin
modeNew:=true;
if Buf_rx[2]<20 then // was in old mode
begin
OutIn(CardAddress,1,1);
givepath; // restart to clean the USB buffer
end;
end
else
modeNew:=false;
end
else
result:=-1;
end;

function SetCurrentDevice(CardNumber: integer): integer; stdcall;
var i:integer;
begin
if open[CardNumber] then
begin
CardAddress:=CardNumber;
for i:=0 to 8 do
Buf_tx[i]:=Buf_cards[i, CardAddress];
result:=CardNumber;
Buf_tx[1]:=6; //check if New version
OutIn(CardAddress,1,1);
if Buf_rx[2]>10 then
begin
modeNew:=true;
if Buf_rx[2]<20 then // was in old mode
begin
OutIn(CardAddress,1,1);
givepath; // restart to clean the USB buffer
end;
end
else
modeNew:=false;
end
else
result:=-1;
end;

procedure CloseDevice; stdcall;
var i:integer;
begin
for i:=0 to 3 do
begin
if open[i] then CloseHandle(hDeviceWrite[i]);
if open[i] then CloseHandle(hDeviceRead[i]);
open[i]:=false;
end;
end;

procedure SetCounterDebounceTime(CounterNro, DebounceTime: integer); stdcall;
var t1:integer;
begin
if CounterNro<1 then CounterNro:=1;
if CounterNro>2 then CounterNro:=2;
t1:= round(0.92.4541POWER(DebounceTime,0.5328));
if t1<1 then t1:=1;
if t1>255 then t1:=255;
Buf_tx[1]:=CounterNro;
if modeNew then
Buf_tx[1]:=10+CounterNro; // 11, 12 set debounce, new mode
Buf_tx[6+CounterNro]:=t1;
OutIn(CardAddress,1,0);
end;

procedure ResetCounter(CounterNro: integer); stdcall;
begin
if CounterNro<1 then CounterNro:=1;
if CounterNro>2 then CounterNro:=2;
Buf_tx[1]:=2+CounterNro;
if modeNew then
Buf_tx[1]:=12+CounterNro; // 13, 14 reset counter, new mode
OutIn(CardAddress,1,0);
end;

procedure OutputAnalogChannel(Channel: integer; Data: integer); stdcall;
begin
if Channel>2 then Channel:=2;
if Channel<1 then Channel:=1;
Buf_tx[2+Channel]:=Data;
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mod
OutIn(CardAddress,1,0);
end;

procedure OutputAllAnalog(Data1: integer; Data2: integer); stdcall;
begin
Buf_tx[3]:=Data1;
Buf_tx[4]:=Data2;
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mode
OutIn(CardAddress,1,0);
end;

procedure ClearAnalogChannel(Channel: integer); stdcall;
begin
if Channel>2 then Channel:=2;
if Channel<1 then Channel:=1;
Buf_tx[2+Channel]:=0;
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mode
OutIn(CardAddress,1,0);
end;

procedure ClearAllAnalog; stdcall;
begin
Buf_tx[3]:=0;
Buf_tx[4]:=0;
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mode
OutIn(CardAddress,1,0);
end;

procedure SetAnalogChannel(Channel: integer); stdcall;
begin
if Channel>2 then Channel:=2;
if Channel<1 then Channel:=1;
Buf_tx[2+Channel]:=255;
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mode
OutIn(CardAddress,1,0);
end;

procedure SetAllAnalog; stdcall;
begin
Buf_tx[3]:=255;
Buf_tx[4]:=255;
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mode
OutIn(CardAddress,1,0);
end;

procedure WriteAllDigital(Data: integer); stdcall;
begin
Buf_tx[2]:=Data;
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mode
OutIn(CardAddress,1,0);
end;

procedure ClearDigitalChannel(Channel: integer); stdcall;
var k:integer;
begin
if Channel>8 then Channel:=8;
if Channel<1 then Channel:=1;
k:=255-round(Exp((Channel-1)*ln(2)));
Buf_tx[2]:=Buf_tx[2] and k; //clear bit
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mode
OutIn(CardAddress,1,0);
end;

procedure ClearAllDigital; stdcall;
begin
Buf_tx[2]:=0;
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mode
OutIn(CardAddress,1,0);
end;

procedure SetDigitalChannel(Channel: integer); stdcall;
var k:integer;
begin
if Channel>8 then Channel:=8;
if Channel<1 then Channel:=1;
k:=round(Exp((Channel-1)*ln(2)));
Buf_tx[2]:=Buf_tx[2] or k; //set bit
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mode
OutIn(CardAddress,1,0);
end;

procedure SetAllDigital; stdcall;
begin
Buf_tx[2]:=255;
Buf_tx[1]:=5;
if modeNew then
Buf_tx[1]:=15; // 15 set digital, new mode
OutIn(CardAddress,1,0);
end;

function ReadDigitalChannel(Channel: integer): Boolean; stdcall;
var n1,k:integer;
begin
if modeNew then
begin
Buf_tx[1]:=16; //16 read digital, new mode
OutIn(CardAddress,1,1);
end
else
OutIn(CardAddress,0,1);
n1:=Buf_rx[1];
k:=integer((n1 and 16)>0)*1+
integer((n1 and 32)>0)*2+
integer((n1 and 1)>0)*4+
integer((n1 and 64)>0)*8+
integer((n1 and 128)>0)*16;
if (k and round(Exp((Channel-1)*ln(2)))) > 0 then
result:=true else result:=false;
end;

function ReadAllDigital: integer; stdcall;
var n1,k:integer;
begin
if modeNew then
begin
Buf_tx[1]:=16; //16 read digital, new mode
OutIn(CardAddress,1,1);
end
else
OutIn(CardAddress,0,1);
n1:=Buf_rx[1];
k:=integer((n1 and 16)>0)*1+
integer((n1 and 32)>0)*2+
integer((n1 and 1)>0)*4+
integer((n1 and 64)>0)*8+
integer((n1 and 128)>0)*16;
result:=k;
end;

function Connected: boolean; stdcall;
var n1,k:integer;
begin
if modeNew then
begin
Buf_tx[1]:=16; //16 read digital, new mode
OutIn(CardAddress,1,1);
if Buf_rx[2]=CardAddress+21 then
result:=true
else
result:=false;
end
else
begin
OutIn(CardAddress,0,1);
if Buf_rx[2]=CardAddress+1 then
result:=true
else
result:=false;
end;
end;

function ReadAnalogChannel(Channel: integer):integer; stdcall;
begin
if Channel>2 then Channel:=2;
if Channel<1 then Channel:=1;
if modeNew then
begin
Buf_tx[1]:= 17; //17 read all analog, new mode
OutIn(CardAddress,1,1);
end
else
OutIn(CardAddress,0,1);
result:=Buf_rx[2+Channel];
end;

procedure ReadAllAnalog(var Data1, Data2: integer); stdcall;
begin
if modeNew then
begin
Buf_tx[1]:= 17; //17 read all analog, new mode
OutIn(CardAddress,1,1);
end
else
OutIn(CardAddress,0,1);
Data1:=Buf_rx[3];
Data2:=Buf_rx[4];
end;

function ReadCounter(CounterNro: integer): integer; stdcall;
begin
if CounterNro<1 then CounterNro:=1;
if CounterNro>2 then CounterNro:=2;
if modeNew then
begin
Buf_tx[1]:=17+CounterNro; //18, 19 read counter 32-bit, new mode
OutIn(CardAddress,1,1);
result:=(Buf_rx[5] + 256Buf_rx[6]+65536Buf_rx[7] + 65536256Buf_rx[8]);
end
else
begin
OutIn(CardAddress,0,1);
result:=(Buf_rx[3+CounterNro2] + 256Buf_rx[4+CounterNro*2]);
end;
end;

function ReadCounter16(CounterNro: integer): integer; stdcall;
begin
if CounterNro<1 then CounterNro:=1;
if CounterNro>2 then CounterNro:=2;
if modeNew then
begin
Buf_tx[1]:=19+CounterNro; //20, 21 read counter 16-bit, new mode
OutIn(CardAddress,1,1);
end
else
OutIn(CardAddress,0,1);
result:=(Buf_rx[3+CounterNro2] + 256Buf_rx[4+CounterNro*2]);
end;

procedure ReadAll(Buffer:Pointer); stdcall;
var p:^integer;
tmp:array[0…7] of integer;
i,n1,k:integer;
begin
if modeNew then
begin
Buf_tx[1]:=22; //22 read all, new mode
OutIn(CardAddress,1,1);
end
else
OutIn(CardAddress,0,1);
for i:=1 to 8 do tmp[i-1]:=Buf_rx[i];
n1:=tmp[0];
k:=integer((n1 and 16)>0)*1+
integer((n1 and 32)>0)*2+
integer((n1 and 1)>0)*4+
integer((n1 and 64)>0)*8+
integer((n1 and 128)>0)*16;
tmp[0]:=k;
p:=Buffer;
for i:=0 to 7 do
begin
p^:=tmp[i];
inc§;
end;
end;

procedure SetPWM(Channel: integer; Data: integer; Frequency: integer); stdcall;
begin
if modeNew then
begin
Buf_tx[1]:=23; // 23 set PWM and frequency
if Channel>2 then Channel:=2;
if Channel<1 then Channel:=1;
if Frequency>3 then Frequency:=3;
if Frequency<1 then Frequency:=1;
Buf_tx[2] := Channel-1; // ch
Buf_tx[3] := Data; // data
Buf_tx[4] := Frequency;
OutIn(CardAddress,1,0);
end;
end;

function ReadBackDigitalOut: Longint; stdcall;
begin
if modeNew then
begin
Buf_tx[1]:=24; // 24 Read Back digital Out
OutIn(CardAddress,1,1);
Buf_cards[2, CardAddress]:=Buf_rx[5]; // update setting
result:=integer(Buf_rx[5]);
end
else
result:=integer(Buf_cards[2, CardAddress]);
end;

procedure ReadBackAnalogOut(Buffer: Pointer); stdcall;
var
p:^integer;
begin
p:=Buffer;
if modeNew then
begin
Buf_tx[1]:=25; // 25 Read Back Analog Out
OutIn(CardAddress,1,1);
Buf_cards[3, CardAddress]:=Buf_rx[6]; // update setting
Buf_cards[4, CardAddress]:=Buf_rx[7]; // update setting
p^:=integer(Buf_rx[6]);
inc§;
p^:=integer(Buf_rx[7]);
end
else
begin
p^:=integer(Buf_cards[3, CardAddress]);
inc§;
p^:=integer(Buf_cards[4, CardAddress]);
end;
end;

function Version: integer; stdcall;
begin
//MessageDlg (‘K8055D.DLL Version 4.0.0.0’, mtInformation , [mbOK], 0);
result:=$05000001;
end;

procedure OutIn(CardAddress:integer; Tx:integer; Rx:integer);
var BytesWritten, BytesRead:DWORD;
i:integer;
begin
for i:=0 to 8 do
Buf_cards[i, CardAddress]:=Buf_tx[i];
for i:=0 to 8 do
Buf_rx[i]:=0;
Buf_tx[0]:=0;
BytesRead:=0;
if open[CardAddress] and (Tx>0) then
begin
WriteFile(hDeviceWrite[CardAddress],Buf_tx,9,BytesWritten,nil);
if BytesWritten=0 then
begin
open[CardAddress]:=false;
CloseHandle(hDeviceWrite[CardAddress]);
CloseHandle(hDeviceRead[CardAddress]);
end;
end;
if open[CardAddress] and (Rx>0) then
begin
ReadFile(hDeviceRead[CardAddress],Buf_rx,9,BytesRead,nil);
if BytesRead=0 then
begin
open[CardAddress]:=false;
CloseHandle(hDeviceWrite[CardAddress]);
CloseHandle(hDeviceRead[CardAddress]);
end;
end;
end;

initialization
for i:=0 to 3 do
begin
open[i]:=false;
hDeviceWrite[i]:= INVALID_HANDLE_VALUE; //Should be invalid before init.
hDeviceRead[i]:= INVALID_HANDLE_VALUE; //Should be invalid before init.
end;
end.[/code][/size]