Build EPICS on windows using MS Compiler

Set EPICS_HOST_ARCH=win32-x86

 

Install the MS Visual Studio .NET 2003 and cygwin as the web page described http://www.aps.anl.gov/epics/base/win32.php

 

The “make” utility is used as GNU make, and program compiler is MS cl.exe which located at the directory just like Microsoft Visual Studio .NET 2003Vc7bin and linker is link.exe at the same directory.

 

Then edit the file cygwin.bat

Before the line “bash --login –I”, add a line as follows:

call "E:Program FilesMicrosoft Visual Studio .NET 2003Vc7binvcvars32.bat"

 

conflicting from the link of cygwin, modify the PATH in cygwin/etc/profile file, just as follows:

from

PATH=/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:$PATH

to

PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin

 

Add the path “<base>/bin/win32-x86” to the system environment variable

 

Then in the cygwin terminal, “cd” epics base directory, and type “make”

 

Examples generated as follows:

<base>/bin/<win32-x86>/makeBaseApp.pl -t example first

<base>/bin/<win32-x86>/makeBaseApp.pl -i -t example first

then

   make

 

copy the file “iocBootiocfirstst.cmd” to example root directory, and modify it like:

-------------------------------------

## Register all support components

dbLoadDatabase("dbd/first.dbd")

first_registerRecordDeviceDriver(pdbbase)

 

## Load record instances

dbLoadRecords("db/dbExample1.db","user=wangjianHost")

dbLoadRecords("db/dbExample2.db","user=wangjianHost,no=1,scan=1 second")

dbLoadRecords("db/dbExample2.db","user=wangjianHost,no=2,scan=2 second")

dbLoadRecords("db/dbExample2.db","user=wangjianHost,no=3,scan=5 second")

dbLoadRecords("db/dbSubExample.db","user=wangjianHost")

 

iocInit()

 

## Start any sequence programs

#seq sncExample,"user=wangjianHost"

-------------------------------------

 

create a file named “startIoc.bat”, and add lines like:

-----------------------------

@echo off

rem Start FIRST IOC

set USER=win32

set EPICS_CA_ADDR_LIST=localhost

set EPICS_CA_AUTO_ADDR_LIST=NO

binwin32-x86first.exe st.cmd

 

Develop a DLL using ActiveDSO for C language

In MS visual studio .net 2003, select File->new…->projects, in “new projects” window, select Visual C++ project->win32->win32 projects, type the project name such as “C2ActiveDSO”, and click OK button

In next window, select DLL option. Then click “finish” button.

 

In the file C2ActiveDSO.cpp, add the export functions as follows:

 

#include "stdio.h"

#import "ActiveDSO.ocx"

 

using namespace ACTIVEDSOLib;

 

extern "C" _declspec(dllexport)

int getIDN(char *strIDN)

{

  // Initialize OLE 2.0 libraries

        if (S_OK != OleInitialize(NULL))

            return FALSE;

 

    // create a smart pointer for ActiveDSO

        _DActiveDSOPtr activeDSO; 

        HRESULT hr = activeDSO.GetActiveObject(__uuidof(ActiveDSO));

        if (FAILED(hr))

        {

            hr = activeDSO.CreateInstance(__uuidof(ActiveDSO));

            if (FAILED(hr))

                _com_issue_error(hr);

        }

 

    // start using the control

        activeDSO->MakeConnection("IP:172.19.68.93");

        activeDSO->WriteString("*IDN?", 1);

        _bstr_t idnString = activeDSO->ReadString(50);

       

        sprintf(strIDN,(const char*) idnString);

        return true;   

}

 

this function get the IDN of wavePro 7100.

 

Develop a DLL using XStream for C language

ActiveDSO is used for remote control while XStream is used for local control. XStream SDK is implemented as MS COM. And we call XStream as dynamic binding.

 

In the file C2XStream.cpp, added the following functions:

#include "AtlBase.h"

CComModule _Module;

#include "AtlCom.h"

CComPtr<IDispatch> spDso;

CComDispatchDriver ddDso; // dispatch ptr. to root of object model (app)

 

extern "C" _declspec(dllexport)

int scopeAutoSetup(void)

{

  ::CoInitialize(NULL);

  HRESULT hr = spDso.CoCreateInstance(L"LeCroy.XStreamDSO");

  if(SUCCEEDED(hr))

  {

    ddDso = spDso;

    // perform an Auto-Setup (app.Autosetup)

    hr = ddDso.Invoke0(L"AutoSetup");

    return 0;

  } else {

    return -1;

  }

 

}

C Function Call DLL’s Function using LoadLibrary

Source code as follows:

 

typedef int (* _getIDN)(char *);

 

int getWaveProIDN(char *strIDN)

{   

    HINSTANCE hDLL;               // Handle to DLL

        _getIDN lpfnGetIDN;

        int bRtnValue;

       

        hDLL = LoadLibrary("C2ActiveDSO"); // C2ActiveDSODLL name

    if (hDLL != NULL)

    {

       lpfnGetIDN = (_getIDN)GetProcAddress(hDLL,

                     "getIDN");

 

       if (!lpfnGetIDN)

       {

           // handle the error

           FreeLibrary(hDLL);

      

           return -1;

       }

       else

       {

           bRtnValue = lpfnGetIDN(strIDN);

       }

    }

       

        return 0;

}

 

A Simple IOC for WavePro 7100 using a “stringin” record

Based on the example source code, we program the simple IOC.

In file xxxSuport.dbd, add this line:

device(stringin,VME_IO,devIpAddr,"waveProIDN")

 

in file ./Db/Example1.db, add this record:

record(stringin, "$(user):waveProIDN")

{

        field(DESC, "wavePro Scope IDN")

        field(DTYP, "waveProIDN")

        field(PINI, "YES")

}

 

create device support file: devWavePro.c as follows:

#include <stddef.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

 

#include "alarm.h"

#include "cvtTable.h"

#include "dbDefs.h"

#include "dbAccess.h"

#include "recGbl.h"

#include "recSup.h"

#include "devSup.h"

#include "link.h"

#include "stringinRecord.h"

#include "epicsExport.h"

 

static long init_record_IP();

static long read_uptime_IP();

typedef struct

{

        long            number;

        DEVSUPFUN       report;

        DEVSUPFUN       init;

        DEVSUPFUN       init_record;

        DEVSUPFUN       get_ioint_info;

        DEVSUPFUN       read;

} DSET;

 

DSET devWaveProIDN={

        5,

        NULL,

        NULL,

        init_record_IP,

        NULL,

        read_uptime_IP,

};

epicsExportAddress(dset,devWaveProIDN);

 

static long init_record_IP(pStringIn)

    struct stringinRecord    *pStringIn;

{

    if(recGblInitConstantLink(&pStringIn->inp,DBF_STRING,&pStringIn->val))

         pStringIn->udf = FALSE;

    return(0);

}

 

static long read_uptime_IP(pStringIn)

    struct stringinRecord    *pStringIn;

{

    char strIDN[256];

   

    getWaveProIDN(strIDN);

    sprintf(pStringIn->val,strIDN);

              

    pStringIn->udf = FALSE;

    return(0);

}

 

the function getWaveProIDN in the activeWavePro.c file which calls C2ActiveDSO.dll

 

in Makefile, add followed lines:

 

xxxSupport_SRCS += devWavePro.c

xxxSupport_SRCS += activeWavePro.c

 

A Simple IOC for WavePro 7100 using a “ao” record

In file xxxSuport.dbd, add

device(ao,      INST_IO, devScopeAutoSetup, "ScopeAutoSetup")

 

in file ../Db/Example1.db, add

record(ao, "$(user):scopeAutoSetup")

{

    field(DESC, "Scope Auto Setup")

    field(DTYP, "ScopeAutoSetup")

}

 

in file devWavePro.c, add

#include <aoRecord.h>

 

DSET devScopeAutoSetup={

        5,

        NULL,

        NULL,

        init_record_ao,

        NULL,

        ao_write,      

};

epicsExportAddress(dset,devScopeAutoSetup);

 

static long init_record_ao(aoRecord *rec)

{

    //add record initial code here

   

    return 0; 

}

static long ao_write(aoRecord *rec)

{

    scopeAutoSetup();

    printf("scope auto setup ok!");

    return(0);

}

 

C Function Call DLL’s Function using LoadLibrary as follows:

 

int scopeAutoSetup(void)

{

    HINSTANCE hDLL;               // Handle to DLL

        _scopeAutoSetup lpfnScopeAutoSetup;

        int bRtnValue;

       

        hDLL = LoadLibrary("C2XStream");

    if (hDLL != NULL)

    {

       lpfnScopeAutoSetup = (_scopeAutoSetup)GetProcAddress(hDLL,

                     "scopeAutoSetup");

 

       if (!lpfnScopeAutoSetup)

       {

           // handle the error

           FreeLibrary(hDLL);

      

           return -1;

       }

       else

       {

           bRtnValue = lpfnScopeAutoSetup();

       }

    }

       

        return 0; 

}

 

A Simple IOC for Tektronix TDS 8000B using a “stringin” record

It is similar to IOC for wavePro 7100, the difference is that this scope used VXI-11 protocol and develop used tekVISA SDK. The tekVISA provide many examples for C language which located VXIpnpWINNTTekVISAVisaSamples. So this IOC does not develop DLL as an interface with the scope SDK

 

In file ../Db/Example1.db, add this record:

record(stringin, "$(user):tekTDSIDN")

{

        field(DESC, "TDS 8000B Scope IDN")

        field(DTYP, "TekTDSIDN")

        field(PINI, "YES")

}

 

in file xxxSupport.dbd, add

device(stringin,INST_IO,devTekTDSIDN,"TekTDSIDN")

 

creative the file devTekTDS.c as follows:

#include <stddef.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

 

#include "alarm.h"

#include "cvtTable.h"

#include "dbDefs.h"

#include "dbAccess.h"

#include "recGbl.h"

#include "recSup.h"

#include "devSup.h"

#include "link.h"

#include "stringinRecord.h"

#include "epicsExport.h"

 

#include <memory.h>

#include <visa.h>

 

static long init_record_IP();

static long read_uptime_IP();

struct {

        long            number;

        DEVSUPFUN       report;

        DEVSUPFUN       init;

        DEVSUPFUN       init_record;

        DEVSUPFUN       get_ioint_info;

        DEVSUPFUN       read;

}devTekTDSIDN={

        5,

        NULL,

        NULL,

        init_record_IP,

        NULL,

        read_uptime_IP,

};

 

epicsExportAddress(dset,devTekTDSIDN);

 

static long init_record_IP(pStringIn)

    struct stringinRecord    *pStringIn;

{

    if(recGblInitConstantLink(&pStringIn->inp,DBF_STRING,&pStringIn->val))

         pStringIn->udf = FALSE;

    return(0);

}

 

 

static long read_uptime_IP(pStringIn)

    struct stringinRecord    *pStringIn;

{

  /*     long status; */

    //long iPAddr=0;

 

    /* status = dbGetLink(&(pStringIn->inp),DBF_STRING, &(pStringIn->val),0,0); */

    /*If return was succesful then set undefined false*/

    /* sprintf(pStringIn->val,"ala %d",get_uptime()); */

    //iPAddr=myIpAddr();

 

    ViSession rm = VI_NULL, vi = VI_NULL;

    ViStatus status;

    ViChar      buffer[56];

    ViUInt32 retCnt;

 

    // Open a default Session

    status = viOpenDefaultRM(&rm);

    if (status < VI_SUCCESS) goto error;

   

    // Open the gpib device at primary address 1, gpib board 8 "GPIB8::1::INSTR",

    // if remote using like "TCPIP::172.19.68.91::INSTR"

    status = viOpen(rm, "TCPIP::172.19.68.91::INSTR", VI_NULL, VI_NULL, &vi);

    if (status < VI_SUCCESS) goto error;

 

    // Send an ID query.

    status = viWrite(vi, (ViBuf) "*idn?", 5, &retCnt);

    if (status < VI_SUCCESS) goto error;

 

    // Clear the buffer and read the response

    memset(buffer, 0, sizeof(buffer));

    status = viRead(vi, (ViBuf) buffer, sizeof(buffer), &retCnt);

    if (status < VI_SUCCESS) goto error;

 

    // Print the response

    //sprintf(strTemp,"%sn",buffer);

 

    // Clean up

    viClose(vi); // Not needed, but makes things a bit more understandable

    viClose(rm);

 

   

   

    sprintf(pStringIn->val,buffer);

      

    /* if(!status)*/  pStringIn->udf = FALSE;

    return(0);

   

error:

    // Report error and clean up

    viStatusDesc(vi, status, buffer);

    fprintf(stderr, "failure: %sn", buffer);

    if (rm != VI_NULL) {

       viClose(rm);

    }

    return -1;

}

 

in file Makefile, add these lines:

#----------------------------------------

#  ADD MACRO DEFINITIONS AFTER THIS LINE

#=============================

 

SYS_PROD_LIBS += visa32

xxxSupport_SYS_LIBS += visa32

 

xxxSupport_SRCS += devTekTDS.c

 

Before make, set LIB=%LIB%;C:VXIpnpWINNTlibmsc