Calling a DLL generated with TMC from MATLAB source from Delphi application

Example: calling a DLL generated with TMC from MATLAB source from Delphi application


The presented example demonstrates how to create a DLL from MATLAB sources (m-files) by means of TMC and call its exported functions from Delphi application code.
In the following example DLL function calculates points of a graph that is plotted by Delphi application. The DLL exported  function is generated from m-code automatically and is called directly from Pascal.

The fragment of Delphi code:


/// File: nicplot.pas

unit nicplot;
interface
uses
  ...
  TmcLib32; (* type definitions for calling function parameters *)


 implementation
{$R *.fmx}
{ TMainForm }
    (* External procedures from TMC Dll: *)
   (* C-interface generated by TMC is
void tmcTestO(int nargout, int nargin,tmsMatrix *F,tmsMatrix *Mag,tmsMatrix *Ph,
tmsMatrix *f1,tmsMatrix *d1,tmsMatrix *f2,tmsMatrix *d2,tmsMatrix *NumFreqs,
tmsMatrix *Fmin__input__tmc,tmsMatrix *Fmax__input__tmc,tmsMatrix *Nint__input__tmc) ;
*)

    procedure  tmcTestO( nargout,nargin:Integer;F,Mag,Ph,f1,d1,f2,d2,NumFreqs,
    Fmin,Fmax,NumInt:PTmcMatrix); cdecl; external 'SIMOR.dll';

...
(* calculate arrays F,Mag,Ph for given parameters w1,d1,w2,d2 *)
(* This function is called on change of these parameters that are entered from the  form  *)
procedure TMainForm.myFiltFreqResp(w1,d1,w2,d2:Double;NumFreqs:Integer;
var  F,Mag,Ph:  array of Double;  Fmin,Fmax: Double; NumInt:Integer);

var
    nargout,nargin:Integer;
    (* variables passed to DLL. Type PTmcMatrix is declared in unit  TmcLib32 *)
    mF,mMag,mPh,mf1,md1,mf2,md2,mNumFreqs,mFmin,mFmax,mNumInt:PTmcMatrix;
    actNumFreqs,k: Integer;
begin
         nargout:=3;nargin:=8;
(* construct input variables *)
         mF := __tmcNewMatrix;
         mMag:= __tmcNewMatrix();
        mPh:= __tmcNewMatrix();
        mf1:= __tmcNewMatrix();
        md1:= __tmcNewMatrix();
        mf2:= __tmcNewMatrix();
        md2:= __tmcNewMatrix();
        mNumFreqs:= __tmcNewMatrix();
        mFmin:= __tmcNewMatrix();
        mFmax:= __tmcNewMatrix();
        mNumInt:= __tmcNewMatrix();
        tmcScalar(mf1,w1);
        tmcScalar(md1,d1);
        tmcScalar(mf2,w2);
        tmcScalar(md2,d2);
        tmcScalar(mNumFreqs,NumFreqs);
        tmcScalar(mFmin,Fmin);
        tmcScalar(mFmax,Fmax);
        tmcScalar(mNumInt,NumInt);
         tmcTestO( nargout,nargin,mF,mMag,mPh,    // outputs
         mf1,md1,mf2,md2,mNumFreqs, mFmin,mFmax,mNumInt   // inputs
         );
          (*  copy outputs: *)
           actNumFreqs := tmcNumElem ( mF );
          if  NumFreqs < actNumFreqs then
                       actNumFreqs:= NumFreqs;
          for  k:=0 to actNumFreqs-1 do
          begin
            F[k]   := mF^.complx.rData[k];
            Mag[k] := mMag^.complx.rData[k];
            Ph[k]  := mPh^.complx.rData[k];
          end;
(* destruct the input variables *)
            tmcFreeLocalVar(mNumInt);
            tmcFreeLocalVar(mFmax);
            tmcFreeLocalVar(mFmin);
            tmcFreeLocalVar(mNumFreqs);
            tmcFreeLocalVar(md2);
            tmcFreeLocalVar(mf2);
            tmcFreeLocalVar(md1);
            tmcFreeLocalVar(mf1);
            tmcFreeLocalVar(mPh);
            tmcFreeLocalVar(mMag);
            tmcFreeLocalVar(mF);
    end;
...
--------------------------------------
/// File: TmcLib32.pas
(*  Interface for TMC run-time *)
unit TmcLib32;
interface
 type
 (* C-code:
struct tag_tmcMatrixDecriptor
{
 enum MATRIX_TYPES m_type;
 unsigned short m_modifier;
 long m_nRows;// first dimension size
 long m_nCols;// multiplication of all other dimensions
 long *m_dims;// array of all dimentions of muli-dim matrix only
};
 struct tag_tmsMatrix
{
 // data is stored by columns
 struct tag_tmcMatrixDecriptor m_desc;// matrix type and dimensions
 union tag_val {
 struct tagStructDef StructDef;
 struct tagReIm complx;
 struct tag_tmsMatrix **m_cells; // cells data (array of cells)
 void (*fnc_ptr)(long,long,...);
 double     scalar_val; // value
 struct tagForStruct ForStruct;
 STRINGCODE  hcode_val; // string code
 } value;
};
*)


      tmcMatrixDecriptor   = record
        m_type : Integer;
       m_modifier : ShortInt;
       m_nRows : Integer; // first dimension size
       m_nCols : Integer; // multiplication of all other dimensions
       m_dims : ^Integer; // array of all dimensions of multi-dim matrix only
       end;
        tagReIm  = record
           rData: array of Double;
           iData: array of Double;
        end;
     (* type for output matrix. So far only numeric array is supported *)
     TmcMatrix = record
        m_desc :   tmcMatrixDecriptor;
        align1 : Integer;
        complx :   tagReIm;
     end;
     PTmcMatrix = ^TmcMatrix;
     (* exported functions *)
     function __tmcNewMatrix: PTmcMatrix;cdecl; external 'tmcrtvc8.dll';
     procedure tmcScalar(dest:PTmcMatrix;x:Double);cdecl; external 'tmcrtvc8.dll';
     procedure tmcFreeLocalVar(src:PTmcMatrix) ;cdecl; external 'tmcrtvc8.dll';
     function  tmcNumElem(x:PTmcMatrix):Integer;cdecl; external 'tmcrtvc8.dll';
implementation
end.

TMC DLL code

For more details refer to examples folder of TMC distribution.
 
/// File: NI_DllEx.c
/// DLL initialization code

#include <windows.h>
#include "tmc.h"

extern   const struct CInit_funcs_table Init_funcs_table ;
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved)
{
 switch (ul_reason_for_call)
 {
 case DLL_PROCESS_ATTACH:
    tmcInitLib(&Init_funcs_table);
   break;
 case DLL_THREAD_ATTACH:
 break;
 case DLL_THREAD_DETACH:
  break;
 case DLL_PROCESS_DETACH:
  tmcFreeLib();
 break;
  }
    return TRUE;
}
///====================================

File: TestO.m
function [F,Mag,Ph]=TestO(f1,d1,f2,d2, NumFreqs,Fmin,Fmax,Nint)
% Calculate 2nd-order filter frequency response
if NumFreqs <2 || f1<= 0 || f2 <=0
    F=0; Mag=0; Ph=0;
    return;
end
if nargin <6
Fmin = min(f1,f2)*0.2;
Fmax = max(f1,f2)/0.2;
end
if (nargin <8)
    Nint=0;
end
F = logspace( log10(Fmin),log10(Fmax), NumFreqs );
w1 = f1*2*pi; w2 = f2*2*pi;
w = F * 2*pi;
[Mag,Ph,num,den]=resp2nd(w1,d1,w2,d2,w);
[Mag2,Ph2,num2,den2]=respint(Nint,w);
Mag = Mag+Mag2;
Ph  = Ph + Ph2;
num=conv(num,num2);
den=conv(den,den2);
% For debugging:
save('result.mat','Mag','Ph','num','den','w1','w2','d1','d2','w','NumFreqs','Fmin','Fmax','F');


%============================================

% File: resp2nd.m
function [Mag,Ph,num,den]=resp2nd(w1,d1,w2,d2,w)
% calculate response of second-order filter
s = j*w;
P = (s.^2 +  2 * d1 * w1 * s + w1 ^ 2) ./ (s.^2 +  2 * d2 * w2 * s + w2 ^ 2  ) * (w2/w1)^2 ;
Mag = 20* log10(abs(P));
Ph = unwrap( angle( P ) ) /pi * 180;
num = [1, 2 * d1 * w1,  w1^2] / w1^2;
den = [1, 2 * d2 * w2,  w2^2] / w2^2;

%File: respint.m
function [Mag,Ph,num,den]=respint(Ni,w)
% calculate response of integrators
s = j*w;
P = 1./ (s.^Ni); % TODO:  Ni must be integer
Mag = 20*log10(abs(P));
Ph = unwrap( angle( P ) ) /pi * 180;
num = 1;
den = [1,zeros(1,Ni)];

%============================================

Remarks:

The interface to output parameters is implemented here in non-safe way due to direct access to the fields of TmcMatrix. It is done in order to demonstrate TMC internals. The better approach is to export from TMC run-time  functions that return pointers to real and imagine parts of the result, i.e. to implement function equivalents to macros mxGetPr(x) and mxGetPi(x).  It is expected to be done in future releases of TMC run-time or may be written in C by user himself.



 

No comments: