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
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.
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;
}
}
Source code as follows:
typedef int (* _getIDN)(char *);
int getWaveProIDN(char *strIDN)
{
HINSTANCE hDLL; // Handle to DLL
_getIDN lpfnGetIDN;
int bRtnValue;
hDLL = LoadLibrary("C2ActiveDSO"); // C2ActiveDSO为DLL name
if (hDLL != NULL)
{
lpfnGetIDN = (_getIDN)GetProcAddress(hDLL,
"getIDN");
if (!lpfnGetIDN)
{
// handle the error
FreeLibrary(hDLL);
return -1;
}
else
{
bRtnValue = lpfnGetIDN(strIDN);
}
}
return 0;
}
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
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;
}
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