23 #include <epicsTypes.h>
24 #include <epicsTime.h>
25 #include <epicsThread.h>
26 #include <epicsString.h>
27 #include <epicsTimer.h>
28 #include <epicsMutex.h>
29 #include <epicsEvent.h>
34 #include "BLFunctions.h"
39 #include <epicsExport.h>
44 asynStatus ECLabDriver::readOctet(asynUser *pasynUser,
char *value,
size_t maxChars,
size_t *nActual,
int *eomReason)
46 int function = pasynUser->reason;
48 const char *functionName =
"readOctet";
49 const char *paramName = NULL;
50 getParamName(
function, ¶mName);
55 if ( value_s.size() > maxChars )
58 if (eomReason) { *eomReason = ASYN_EOM_CNT | ASYN_EOM_END; }
59 asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
60 "%s:%s: function=%d, name=%s, value=\"%s\" (TRUNCATED from %d chars)\n",
61 driverName, functionName,
function, paramName, value_s.substr(0,*nActual).c_str(), value_s.size());
65 *nActual = value_s.size();
66 if (eomReason) { *eomReason = ASYN_EOM_END; }
67 asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
68 "%s:%s: function=%d, name=%s, value=\"%s\"\n",
69 driverName, functionName,
function, paramName, value_s.c_str());
71 strncpy(value, value_s.c_str(), maxChars);
74 catch(
const std::exception& ex)
76 epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
77 "%s:%s: status=%d, function=%d, name=%s, value=\"%s\", error=%s",
78 driverName, functionName, status,
function, paramName, value_s.c_str(), ex.what());
80 if (eomReason) { *eomReason = ASYN_EOM_END; }
89 static const std::string ecc_dir = macEnvExpand(
"$(ECLAB)/ecc/");
90 int function = pasynUser->reason;
91 asynStatus status = asynSuccess;
92 const char *paramName = NULL;
93 getParamName(
function, ¶mName);
94 const char* functionName =
"writeOctet";
95 std::string value_s(value, maxChars);
97 getAddress(pasynUser, &addr);
102 char* valueCopy = strdup(value_s.c_str());
103 char *tok_save = NULL;
104 char * tech = epicsStrtok_r(valueCopy,
" ,;", &tok_save);
106 std::map<std::string,int> tech_count;
109 if (tech_count.find(tech) == tech_count.end())
111 tech_count[tech] = 0;
115 tech = epicsStrtok_r(NULL,
" ,;", &tok_save);
124 bool first = ( i == 0 );
126 std::vector<TEccParam_t> values;
128 if (values.size() > 0)
130 params.pParams = &(values[0]);
134 params.pParams = NULL;
136 params.len = values.size();
137 std::string ecc_file = ecc_dir +
m_techniques[i].name +
"4.ecc";
138 std::replace(ecc_file.begin(), ecc_file.end(),
'/',
'\\');
142 asynPortDriver::writeOctet(pasynUser, value, maxChars, nActual);
143 asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
144 "%s:%s: function=%d, name=%s, value=%s\n",
145 driverName, functionName,
function, paramName, value_s.c_str());
146 *nActual = value_s.size();
149 catch(
const std::exception& ex)
151 epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
152 "%s:%s: status=%d, function=%d, name=%s, value=%s, error=%s",
153 driverName, functionName, status,
function, paramName, value_s.c_str(), ex.what());
161 int function = pasynUser->reason;
162 asynStatus status = asynSuccess;
163 const char *paramName = NULL;
164 getParamName(
function, ¶mName);
165 const char* functionName =
"writeFloat64";
167 getAddress(pasynUser, &addr);
171 asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
172 "%s:%s: function=%d, name=%s, value=%f\n",
173 driverName, functionName,
function, paramName, value);
177 catch(
const std::exception& ex)
179 epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
180 "%s:%s: status=%d, function=%d, name=%s, value=%f, error=%s",
181 driverName, functionName, status,
function, paramName, value, ex.what());
188 static const std::string ecc_dir = macEnvExpand(
"$(ECLAB)/ecc/");
189 int function = pasynUser->reason;
190 asynStatus status = asynSuccess;
191 const char *paramName = NULL;
192 getParamName(
function, ¶mName);
193 const char* functionName =
"writeInt32";
195 getAddress(pasynUser, &addr);
215 std::vector<TEccParam_t> values;
218 for(
int j=0; j<values.size(); j += maxupdate)
220 params.pParams = &(values[j]);
221 int n = values.size() - j;
222 params.len = (n > maxupdate ? maxupdate : n);
223 std::string ecc_file = ecc_dir +
m_techniques[i].name +
"4.ecc";
224 std::replace(ecc_file.begin(), ecc_file.end(),
'/',
'\\');
237 asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
238 "%s:%s: function=%d, name=%s, value=%d\n",
239 driverName, functionName,
function, paramName, value);
243 catch(
const std::exception& ex)
245 epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
246 "%s:%s: status=%d, function=%d, name=%s, value=%d, error=%s",
247 driverName, functionName, status,
function, paramName, value, ex.what());
255 fprintf(fp,
"ECLabDriver report\n");
256 std::ostringstream oss;
258 fwrite(oss.str().c_str(), 1, oss.str().size(), fp);
259 asynPortDriver::report(fp, details);
268 : asynPortDriver(portName,
271 asynInt32Mask | asynInt32ArrayMask | asynInt8ArrayMask | asynFloat64Mask | asynFloat32ArrayMask | asynOctetMask | asynDrvUserMask,
272 asynInt32Mask | asynInt32ArrayMask | asynInt8ArrayMask | asynFloat64Mask | asynFloat32ArrayMask | asynOctetMask,
279 const char *functionName =
"ECLabDriver";
280 static const std::string ecc_dir = macEnvExpand(
"$(ECLAB)/ecc/");
307 setStringParam(
P_host,
"unknown");
308 setIntegerParam(
P_devCode, KBIO_DEV_UNKNOWN);
316 if ( !strcmp(ip,
"SIM") )
322 unsigned ver_size =
sizeof(
version);
331 std::string kernel_file = ecc_dir +
"kernel4.bin";
332 std::replace(kernel_file.begin(), kernel_file.end(),
'/',
'\\');
333 std::string xlx_file = ecc_dir +
"Vmp_iv_0395_aa.xlx";
334 std::replace(xlx_file.begin(), xlx_file.end(),
'/',
'\\');
337 setStringParam(
P_host, ip);
342 if (epicsThreadCreate(
"ECLabValuesTask",
343 epicsThreadPriorityMedium,
344 epicsThreadGetStackSize(epicsThreadStackMedium),
347 printf(
"%s:%s: epicsThreadCreate failure\n",
driverName, functionName);
350 if (epicsThreadCreate(
"ECLabDataTask",
351 epicsThreadPriorityMedium,
352 epicsThreadGetStackSize(epicsThreadStackMedium),
355 printf(
"%s:%s: epicsThreadCreate failure\n",
driverName, functionName);
381 setIntegerParam(chan,
P_memFilled, cvals.MemFilled);
382 setDoubleParam(chan,
P_currEWE, cvals.Ewe);
383 setDoubleParam(chan,
P_currECE, cvals.Ece);
384 setDoubleParam(chan,
P_currI, cvals.I);
385 setDoubleParam(chan,
P_currTIME, cvals.ElapsedTime);
394 TCurrentValues_t cvals;
395 TChannelInfos_t cinfo;
400 for(
int i=0; i<
m_infos.NumberOfChannels; ++i)
409 catch(
const std::exception& ex)
411 errlogSevPrintf(errlogInfo,
"%s", ex.what());
418 setIntegerParam(i,
P_numTech, cinfo.NbOfTechniques);
424 callParamCallbacks();
428 epicsThreadSleep(1.0);
434 return (((__int64)thigh << 32) + tlow) * time_base + start_time;
438 int loop,
double start_time,
double time_base, TDataBuffer_t* dbuffer)
440 unsigned*
data = dbuffer->data;
444 float ewe, currI, freq, eweMod, currIMod, phaseZwe,eceMod, iceMod;
446 if (process_index == 0)
450 std::cerr <<
"PEIS: incorrect number of columns in data for process 0" << std::endl;
453 for(
int i=0; i<nrows; ++i)
456 t =
getTime(data[idx + 0], data[idx + 1], start_time, time_base);
457 BL_ConvertNumericIntoSingle(data[idx + 2], &ewe);
458 BL_ConvertNumericIntoSingle(data[idx + 3], &currI);
459 fs0 << t <<
"," << ewe <<
"," << currI <<
"\n";
462 else if (process_index == 1)
466 std::cerr <<
"PEIS: incorrect number of columns in data for process 1" << std::endl;
469 for(
int i=0; i<nrows; ++i)
472 BL_ConvertNumericIntoSingle(data[idx + 0], &freq);
473 BL_ConvertNumericIntoSingle(data[idx + 1], &eweMod);
474 BL_ConvertNumericIntoSingle(data[idx + 2], &currIMod);
475 BL_ConvertNumericIntoSingle(data[idx + 3], &phaseZwe);
476 BL_ConvertNumericIntoSingle(data[idx + 4], &ewe);
477 BL_ConvertNumericIntoSingle(data[idx + 5], &currI);
478 BL_ConvertNumericIntoSingle(data[idx + 7], &eceMod);
479 BL_ConvertNumericIntoSingle(data[idx + 8], &iceMod);
480 BL_ConvertNumericIntoSingle(data[idx + 9], &phaseZce);
481 BL_ConvertNumericIntoSingle(data[idx + 10], &ece);
482 BL_ConvertNumericIntoSingle(data[idx + 13], &tf);
483 fs1 << tf <<
"," << freq <<
"," << eweMod
484 <<
"," << currIMod <<
"," << phaseZwe <<
"," << ewe
485 <<
"," << currI <<
"," << eceMod <<
"," << iceMod
486 <<
"," << phaseZce <<
"," << ece << std::endl;
492 int loop,
double start_time,
double time_base, TDataBuffer_t* dbuffer)
494 unsigned*
data = dbuffer->data;
500 std::cerr <<
"OCV: incorrect number of columns in data" << std::endl;
503 for(
int i=0; i<nrows; ++i)
506 t =
getTime(data[idx + 0], data[idx + 1], start_time, time_base);
507 ret = BL_ConvertNumericIntoSingle(data[idx + 2], &ewe);
509 fs << t <<
"," << ewe <<
"\n";
515 TCurrentValues_t cvals;
517 TDataBuffer_t dbuffer;
519 std::fstream all_fs0[100], all_fs1[100];
520 unsigned file_index[100];
522 char fileprefix[256];
526 memset(file_index, 0,
sizeof(file_index));
532 for(
int i=0; i<
m_infos.NumberOfChannels; ++i)
534 std::fstream& fs0 = all_fs0[i];
535 std::fstream& fs1 = all_fs1[i];
549 callParamCallbacks();
559 catch(
const std::exception& ex)
561 errlogSevPrintf(errlogInfo,
"%s", ex.what());
565 callParamCallbacks();
568 pstm = localtime(&now);
569 strftime(tbuff,
sizeof(tbuff),
"%Y%m%dT%H%M%S", pstm);
570 if (dinfo.TechniqueID == KBIO_TECHID_OCV)
572 if ( cvals.State == KBIO_STATE_RUN && !(fs0.is_open()) )
574 getStringParam(
P_filePrefix,
sizeof(fileprefix), fileprefix);
575 sprintf(filename,
"%s_%s_%d_0.csv", fileprefix, tbuff, i);
576 fs0.open(filename, std::ios::out);
579 processOCVData(fs0, dinfo.NbRows, dinfo.NbCols, dinfo.TechniqueIndex, dinfo.ProcessIndex,
580 dinfo.loop, dinfo.StartTime, cvals.TimeBase, &dbuffer);
582 else if (dinfo.TechniqueID == KBIO_TECHID_PEIS)
584 if ( cvals.State == KBIO_STATE_RUN && !(fs0.is_open()) )
586 getStringParam(
P_filePrefix,
sizeof(fileprefix), fileprefix);
587 sprintf(filename,
"%s_%s_%d_0.csv", fileprefix, tbuff, i);
588 fs0.open(filename, std::ios::out);
589 fs0 <<
"Time,Ewe,I\n";
590 sprintf(filename,
"%s_%s_%d_1.csv", fileprefix, tbuff, i);
591 fs1.open(filename, std::ios::out);
592 fs1 <<
"Time,Freq,Mod Ewe,Mod I,Phase Zwe,Ewe,I,Mod Ece,Mod Ice,Phase Zce,Ece\n";
594 processPEISData(fs0, fs1, dinfo.NbRows, dinfo.NbCols, dinfo.TechniqueIndex, dinfo.ProcessIndex,
595 dinfo.loop, dinfo.StartTime, cvals.TimeBase, &dbuffer);
598 if (cvals.State == KBIO_STATE_STOP && cvals.MemFilled == 0)
616 callParamCallbacks();
622 epicsThreadSleep(2.0);
626 epicsThreadSleep(0.2);
643 catch(
const std::exception& ex)
645 errlogSevPrintf(errlogFatal,
"ECLabConfigure failed: %s\n", ex.what());
652 static const iocshArg
initArg0 = {
"portName", iocshArgString};
653 static const iocshArg
initArg1 = {
"ip", iocshArgString};
656 static const iocshFuncDef
initFuncDef = {
"ECLabConfigure",
sizeof(
initArgs) /
sizeof(iocshArg*), initArgs};
EPICS Asyn port driver class.
void processPEISData(std::fstream &fs0, std::fstream &fs1, int nrows, int ncols, int technique_index, int process_index, int loop, double start_time, double time_base, TDataBuffer_t *dbuffer)
void processOCVData(std::fstream &fs, int nrows, int ncols, int technique_index, int process_index, int loop, double start_time, double time_base, TDataBuffer_t *dbuffer)
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value)
static void LoadFirmware(int ID, uint8 *pChannels, int *pResults, uint8 Length, bool ShowGauge, bool ForceReload, const char *BinFile, const char *XlxFile)
epicsExportRegistrar(ECLabRegister)
void getTechniqueParams(const std::string &technique, int addr, std::vector< TEccParam_t > &values, bool changes_only)
static void GetChannelInfos(int ID, uint8 ch, TChannelInfos_t *pInfos)
Header for ECLabDriver class.
static void ECLabDataTaskC(void *arg)
static bool IsChannelPlugged(int ID, uint8 ch)
#define P_currSTATEString
static void GetCurrentValues(int ID, uint8 channel, TCurrentValues_t *pValues)
virtual void report(FILE *fp, int details)
EPICS driver report function for iocsh dbior command.
void updateCvals(int chan, TCurrentValues_t &cvals)
#define P_memFilledString
void setECIntegerParam(asynPortDriver *driver, int addr, int id, epicsInt32 value)
static void StartChannel(int ID, uint8 channel)
std::vector< techinfo > m_techniques
static const char * version
static void ECLabRegister(void)
Register new commands with EPICS IOC shell.
#define P_startChannelString
static void GetLibVersion(char *pVersion, unsigned int *psize)
int ECLabConfigure(const char *portName, const char *ip)
The function is registered via EClabRegister().
void addAllParameters(asynPortDriver *driver)
static void StopChannel(int ID, uint8 channel)
static void Connect(const char *address, uint8 TimeOut, int *pID, TDeviceInfos_t *pInfos)
strncpy(pVersion, version,*psize)
#define P_currRCOMPString
#define P_filePrefixString
static const iocshFuncDef initFuncDef
static void testConnect(int ID)
static const char * driverName
Name of driver for use in message printing.
void printParams(std::ostream &os)
ECLabDriver(const char *portName, const char *ip)
Constructor for the ECLabDriver class.
#define P_currTimeBaseString
virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value)
double getTime(unsigned thigh, unsigned tlow, double start_time, double time_base)
Provide an interface to EC lab functions, converting error codes into C++ exceptions.
static void UpdateParameters(int ID, uint8 channel, int TechIndx, TEccParams_t Params, const char *EccFileName)
memset(TExpInfos, 0, sizeof(TExperimentInfos_t))
#define P_stopChannelString
static void ECLabValuesTaskC(void *arg)
void setECSingleParam(asynPortDriver *driver, int addr, int id, epicsFloat64 value)
static void GetData(int ID, uint8 channel, TDataBuffer_t *pBuf, TDataInfos_t *pInfos, TCurrentValues_t *pValues)
static void LoadTechnique(int ID, uint8 channel, char *pFName, TEccParams_t Params, bool FirstTechnique, bool LastTechnique, bool DisplayParams)
#define P_updateParamsString
static void initCallFunc(const iocshArgBuf *args)
#define P_numChannelsString
#define P_defineTechString
static const iocshArg initArg0
A name for the asyn driver instance we will create - used to refer to it from EPICS DB files...
static const iocshArg initArg1
IP address used.
virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t maxChars, size_t *nActual)
static const iocshArg *const initArgs[]