Hello Guest it is November 14, 2019, 09:10:54 PM

Author Topic: Connecting and controlling Mach4 through an object pascal applicaton  (Read 803 times)

0 Members and 1 Guest are viewing this topic.

Thought I would throw out an example of how to connect and utilize Mach4's Mach4IPC.dll  This dll contains all of the listed APIs.  This example only has a few of those listed.  Enough to demonstrate

This code would be used by any application:

Code: [Select]
unit Mach4DllWrapper;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes;

  //define each function that you might call
  type TmcIpcInit = function(ipAddr: pChar):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  type TmcGetInstance = function:integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  type TmcIpcCleanup = function:integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  type TmcRegGetValue =  function( hReg:integer;value:pdouble):integer ;{$IFDEF WIN32} stdcall; {$ENDIF}
  type TmcCntlLoadGcodeFile = function(mInst:integer;FileToLoad:pChar):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  Type TmcCntlCloseGCodeFile = function(mInst:integer):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  Type TmcCntlRewindFile = function(mInst:integer):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  type TmcCntlEStop = function( mInst:integer):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  Type TmcCntlEnable =function( mInst:integer;State:Boolean):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  type TmcCntlReset = function( mInst:integer):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  Type TmcAxisGetPos = function( mInst:integer; axisId:integer; val:pdouble):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  Type TmcAxisSetPos = function( mInst:integer; axisId:integer; val:pdouble):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  Type TmcCntlCycleStart = function(mInst:integer):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  Type TmcCntlCycleStop = function(mInst:integer):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  Type TmcCntlGcodeExecuteWait = function(mInst:integer;commands:pChar):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  Type TmcAxisHome = function( mInst:integer; axisId:integer):integer;{$IFDEF WIN32} stdcall; {$ENDIF}
  Type TmcAxisIsHomed = function( mInst:integer;axisId:integer;homed:pBoolean):integer;{$IFDEF WIN32} stdcall; {$ENDIF}

type TMach4Control=class(TObject)
  private
    fLoaded    : Boolean;
    fConnected : Boolean;
  public
    mcIpcInit          :TmcIpcInit;
    mcGetInstance      :TmcGetInstance;
    mcIpcCleanup       :TmcIpcCleanup;
    mcCntlEStop        :TmcCntlEStop;
    mcCntlEnable       :TmcCntlEnable;
    mcCntlReset        :TmcCntlReset;
    mcRegGetValue      :TmcRegGetValue;
    mcCntlLoadGcodeFile:TmcCntlLoadGcodeFile;
    mcCntlCloseGcodeFile:TmcCntlCloseGcodeFile;
    mcCntlRewindFile   :TmcCntlRewindFile;
    mcAxisGetPos       :TmcAxisGetPos;
    mcAxisSetPos       :TmcAxisSetPos;
    mcCntlCycleStart   :TmcCntlCycleStart;
    mcCntlCycleStop    :TmcCntlCycleStop;
    mcCntlGcodeExecuteWait:TmcCntlGcodeExecuteWait;
    mcAxisHome        :TmcAxisHome;
    mcAxisIsHomed     :TmcAxisIsHomed;

    Handle             :Thandle;
    mInst              :Integer;
    property Loaded    :Boolean read fLoaded write fLoaded;
    property Connected :Boolean read fConnected write fConnected;

    function init(dllLoc:pChar):Boolean;
    procedure doConnect(myIP:pChar);
    procedure cleanUp;
    constructor create;
end;

function ErrGetProcAddress(h:THandle;procName:pAnsiChar):FARPROC;

type handle = Integer;


implementation

function ErrGetProcAddress(h:THandle;procName:pAnsiChar):FARPROC;
begin
  result:=getProcAddress(h,procName);
  if not assigned(result) then
    raise exception.Create('DLL does not contain function: '+ProcName);
    // usually a typo in the function name if failed
end;

constructor TMach4Control.create;
begin
  inherited;
end;

function TMach4Control.init(dllLoc:pChar):Boolean;
begin
  //get the address of each function in the dll
  Handle := LoadLibrary(dllLoc);//'c:\Mach4Hobby\mach4IPC.dll');
  Loaded:= Handle <> 0 ;
  mcIpcInit:=ErrGetProcAddress(handle,'mcIpcInit');
  mcIpcCleanup:=ErrGetProcAddress(handle,'mcIpcCleanup');
  mcCntlEStop:=ErrGetProcAddress(handle,'mcCntlEStop');
  mcCntlEnable:=ErrGetProcAddress(handle,'mcCntlEnable');
  mcCntlReset:=ErrGetProcAddress(handle,'mcCntlReset');
  mcCntlLoadGcodeFile:=ErrGetProcAddress(handle,'mcCntlLoadGcodeFile');
  mcCntlCloseGcodeFile:=ErrGetProcAddress(handle,'mcCntlCloseGCodeFile');
  mcCntlRewindFile:=ErrGetProcAddress(handle,'mcCntlRewindFile');
  mcAxisGetPos:=ErrGetProcAddress(handle,'mcAxisGetPos');
  mcAxisSetPos:=ErrGetProcAddress(handle,'mcAxisSetPos');
  mcCntlCycleStart:=ErrGetProcAddress(handle,'mcCntlCycleStart');
  mcCntlCycleStop:=ErrGetProcAddress(handle,'mcCntlCycleStop');
  mcCntlGcodeExecuteWait:=ErrGetProcAddress(handle,'mcCntlGcodeExecuteWait');
  mcAxisHome:=ErrGetProcAddress(handle,'mcAxisHome');
  mcAxisIsHomed:=ErrGetProcAddress(handle,'mcAxisIsHomed');
end;

procedure TMach4Control.doConnect(myIP:pChar);
begin
  // connect to a running of Mach4
  if @mcIpcInit <> nil then
  begin
    mInst:=mcIpcInit(myIP);
    Connected:=(mInst=0);
  end;
end;

procedure TMach4Control.cleanUp;
begin
   if @mcIpcCleanup <> nil then
        mcIpcCleanup;
end;

end.


This code is for the application shown in the jpg

Code: [Select]
unit frmMach4AccessMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, JvExStdCtrls, JvEdit, JvValidateEdit, Mask,
  JvExMask, JvToolEdit, JvExControls, JvSpeedButton, TILed,
  MachLed, ExtCtrls,  Mach4DllWrapper;


type
  TForm1 = class(TForm)
    btnLoadFile: TButton;
    stat1: TStatusBar;
    btnEnable: TButton;
    btnCycleStart: TButton;
    btnCycleStop: TButton;
    btnRewind: TButton;
    btnCloseFile: TButton;
    btnMDIexecute: TButton;
    mmo1: TMemo;
    eGCodeFile: TJvFilenameEdit;
    pnl1: TPanel;
    lbl1: TLabel;
    eXdro: TJvValidateEdit;
    btnZeroXdro: TJvSpeedButton;
    btnXhome: TJvSpeedButton;
    MachLedxDro: tMachLed;
    MachLed2: tMachLed;
    pnl2: TPanel;
    lbl3: TLabel;
    btnZeroZdro: TJvSpeedButton;
    btnZhome: TJvSpeedButton;
    MachLedZdro: tMachLed;
    MachLed5: tMachLed;
    eZdro: TJvValidateEdit;
    procedure btnLoadFileClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure btnEnableClick(Sender: TObject);
    procedure btnCycleStartClick(Sender: TObject);
    procedure btnCycleStopClick(Sender: TObject);
    procedure btnCloseFileClick(Sender: TObject);
    procedure btnRewindClick(Sender: TObject);
    procedure btnMDIexecuteClick(Sender: TObject);
    procedure btnZeroXdroClick(Sender: TObject);
    procedure btnXhomeClick(Sender: TObject);
    procedure btnZhomeClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


var
  Form1: TForm1;
  myIP: string = '127.0.0.1';
  dllLocation: string = 'c:\Mach4Hobby\mach4IPC.dll';
  mc:TMach4Control;

implementation

{$R *.dfm}


procedure TForm1.FormCreate(Sender: TObject);
var
  d:Double;
  homed:boolean;
begin
   mc:=TMach4Control.create;
   mc.init(pChar(DllLocation));      //load the dll and find the function locations
   if mc.Loaded then
   begin
     stat1.Panels[0].Text:='Loaded';  //Status: successfully Loaded
     btnLoadFile.Enabled:=mc.Loaded;  //determine whoter to enable or not
     btnEnable.Enabled:=mc.Loaded;    //determine whoter to enable or not
   end else
   begin
     stat1.Panels[0].Text:='Load Failure';
     exit;
   end;
   stat1.Panels[1].Text:='Connecting...';
   application.ProcessMessages;
  if mc=nil then
    exit;
  if mc.Connected then
    exit;
  mc.doConnect(pChar(myIP));    //connect to a running Mach4 instance
  if mc.Connected then
    stat1.Panels[1].Text:='Connected to Mach4'
  else
    stat1.Panels[1].Text:='Failed to Connect';
  application.ProcessMessages;
  mc.mcAxisGetPos(mc.mInst,0,@d);  //get the Xdro position-need to write a thread to update
  eXdro.Value:=d;
  mc.mcAxisGetPos(mc.mInst,2,@d);  //get the Zdro position-need to write a thread to update
  eZdro.Value:=d;
  mc.mcAxisIsHomed(mc.mInst,0,@homed);
  if homed then
    MachLedxDro.Color:=clGreen
  else
    MachLedxDro.Color:=clMaroon;
  mc.mcAxisIsHomed(mc.mInst,2,@homed);
  if homed then
    MachLedzDro.Color:=clGreen
  else
    MachLedzDro.Color:=clMaroon;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//clean up before exiting
  if mc<>nil then
    mc.mcIpcCleanup;
  freeLibrary(mc.Handle);
end;

procedure TForm1.btnLoadFileClick(Sender: TObject);
var
  i:integer;
  s:string;
begin
  //load GCodeFile listed in edit control
    stat1.Panels[2].Text:='Loading GCode file';
    application.ProcessMessages;
    s:=eGcodeFile.FileName;
    i:=mc.mcCntlLoadGcodeFile(mc.mInst,pChar(eGcodeFile.filename));
    stat1.Panels[2].Text:='Return Code: '+intToStr(i);
end;

procedure TForm1.btnEnableClick(Sender: TObject);
begin
  //code to enable and disable Mach and update button state
  if  btnEnable.Caption='&Enable' then
  begin
    mc.mcCntlEnable(mc.mInst,True);
    btnEnable.Caption:='&Disable';
  end else
  begin
    mc.mcCntlEStop(mc.mInst);
    btnEnable.Caption:='&Enable';
  end;
  btnCycleStart.Enabled:=btnEnable.Caption<>'&Enable';
  btnCycleStop.Enabled:=btnEnable.Caption<>'&Enable';
end;

procedure TForm1.btnCycleStartClick(Sender: TObject);
begin
  mc.mcCntlCycleStart(mc.mInst);
  btnCycleStop.SetFocus;
end;

procedure TForm1.btnCycleStopClick(Sender: TObject);
begin
  mc.mcCntlCycleStop(mc.mInst);
end;

procedure TForm1.btnCloseFileClick(Sender: TObject);
begin
  mc.mcCntlCloseGcodeFile(mc.mInst);
  mc.mcCntlRewindFile(mc.mInst);//close file doesnt clear gcode window
end;

procedure TForm1.btnRewindClick(Sender: TObject);
begin
  mc.mcCntlRewindFile(mc.mInst);
end;

procedure TForm1.btnMDIexecuteClick(Sender: TObject);
begin
  //execute gcode in the momo component
  mc.mcCntlGcodeExecuteWait(mc.mInst,pChar(mmo1.Text));
end;

procedure TForm1.btnZeroXdroClick(Sender: TObject);
var
  d:double;
begin
  d:=0;
  mc.mcAxisSetPos(mc.mInst,0,@d);
end;

procedure TForm1.btnXhomeClick(Sender: TObject);
begin
  if mc.mcAxisHome(mc.mInst,0)=0 then
    MachLedxDro.color:=clGreen;
end;

procedure TForm1.btnZhomeClick(Sender: TObject);
begin
  if mc.mcAxisHome(mc.mInst,2)=0 then
    MachLedxDro.color:=clGreen;
end;

end.


Hope this saves someone some time.


RT