Commit dc3e73c2 authored by kpetersn's avatar kpetersn
Browse files

Created a mono thread task. The only time the IOC didn't crash was when it...

Created a mono thread task.  The only time the IOC didn't crash was when it was failing to connect to the controller.  It segfaults when it does.
parent d2fa461b
#include <stdio.h>
#include <stdio.h> /* defines FILENAME_MAX */
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif
#include "dllImports.h"
#include <iocsh.h>
#include <epicsExport.h>
#include <epicsString.h>
#include <epicsThread.h>
#include <epicsEvent.h>
#include "Linkam_T96.h"
......@@ -18,8 +26,17 @@ Linkam::Linkam(const char *portName, const char *serialPort) : asynPortDriver(po
0, 0) /* Default priority and stack size */
{
serialPort_ = epicsStrDup(serialPort);
bool status;
static const char *functionName = "Linkam";
connectFlag_ = 0;
disconnectFlag_ = 0;
getValueFlag_ = 0;
GetCurrentDir(currentPath_, sizeof(currentPath_));
currentPath_[sizeof(currentPath_) - 1] = '\0'; /* not really required */
printf ("The current working directory is %s\n\n", currentPath_);
createParam(temperatureInValueString, asynParamFloat64, &temperatureInValue_);
createParam(rampLimitOutValueString, asynParamFloat64, &rampLimitOutValue_);
createParam(rampLimitInValueString, asynParamFloat64, &rampLimitInValue_);
......@@ -28,6 +45,77 @@ Linkam::Linkam(const char *portName, const char *serialPort) : asynPortDriver(po
createParam(heaterPowerInValueString, asynParamFloat64, &heaterPowerInValue_);
createParam(heatingOutValueString, asynParamInt32, &heatingOutValue_);
/* Create the epicsEvents for signaling to the mono task */
this->connectEventId = epicsEventCreate(epicsEventEmpty);
if (!this->connectEventId) {
printf("%s:%s epicsEventCreate failure for connect event\n",
driverName, functionName);
return;
}
this->doWorkEventId = epicsEventCreate(epicsEventEmpty);
if (!this->doWorkEventId) {
printf("%s:%s epicsEventCreate failure for do work event\n",
driverName, functionName);
return;
}
this->initEventId = epicsEventCreate(epicsEventEmpty);
if (!this->initEventId) {
printf("%s:%s epicsEventCreate failure for init event\n",
driverName, functionName);
return;
}
/* Create the thread that calls the mono library */
status = (epicsThreadCreate("LinkamMonoTask", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC)LinkamMonoTaskC, this) == NULL);
if (status) {
printf("%s:%s epicsThreadCreate failure for Linkam Mono task\n",
driverName, functionName);
return;
}
//epicsEventWait(this->initEventId);
// Must be in the directory with the DLL when this line is executed
//LoadMonoLibrary("LinkamCommsDll.dll");
//epicsThreadSleep(2.0);
// Force the device to connect now
//connect(this->pasynUserSelf);
connectFlag_ = 1;
}
Linkam::~Linkam()
{
// Force the controller to disconnect
disconnect(this->pasynUserSelf);
}
static void LinkamMonoTaskC(void *drvPvt) {
Linkam *pPvt = (Linkam *)drvPvt;
pPvt->LinkamMonoTask();
}
/** This thread calls readImage to retrieve new image data from the camera and
* does the callbacks to send it to higher layers. It implements the logic for
* single, multiple or continuous acquisition. */
void Linkam::LinkamMonoTask()
{
asynStatus status;
int cdStat;
epicsFloat64 *value;
cdStat = chdir(currentPath_);
printf("cdStat = %i\n", cdStat);
this->lock();
// Must be in the directory with the DLL when this line is executed
LoadMonoLibrary("LinkamCommsDll.dll");
......@@ -37,19 +125,80 @@ Linkam::Linkam(const char *portName, const char *serialPort) : asynPortDriver(po
// Call to LinkamCommsDll.Comms.GetDllVersion().
libraryVersion_ = GetDllVersion();
printf("Comms Library Version %s\n", libraryVersion_);
// Start poller? For now just initialize the temperature
// Force the device to connect now
connect(this->pasynUserSelf);
//epicsThreadSleep(5.0);
}
//epicsEventSignal(this->initEventId);
epicsThreadSleep(15.0);
/* Loop forever */
while (1) {
/* Wait to connect */
if (!connectFlag_)
{
this->unlock();
epicsEventWait(this->connectEventId);
this->lock();
}
/*
* Wrapped call to LinkamCommsDll.Comms.OpenComms()
*
* OpenComms(
* true, bool bConnect: set to true to connect and false to disconnect
* 1, UInt32 u32Commtype: Connection protocol (0: USB, 1: Serial)
* 3); UInt32 u32CommPort: Set to the COMM port that the controller is connected to. (e.g. COMM port 3)
*/
// OpenComms only works for Windows-style numbering of COM ports
//commStatus_ = OpenComms(true, 1, 0);
commStatus_ = OpenCommsFromDevice(true, serialPort_);
/* We found the controller and everything is OK. Signal to asynManager that we are connected. */
status = pasynManager->exceptionConnect(this->pasynUserSelf);
while (!disconnectFlag_)
{
this->unlock();
epicsEventWait(this->doWorkEventId);
this->lock();
if (getValueFlag_)
{
switch (valueToGet_)
{
case u32Heater1TempR:
*value = GetValue(u32Heater1TempR);
setDoubleParam(asynFunction_, *value);
break;
case u32Heater1LimitRW:
*value = GetValue(u32Heater1LimitRW);
setDoubleParam(asynFunction_, *value);
break;
case u32Heater1RateRW:
*value = GetValue(u32Heater1RateRW);
setDoubleParam(asynFunction_, *value);
break;
case u32Heater1PowerR:
*value = GetValue(u32Heater1PowerR);
setDoubleParam(asynFunction_, *value);
break;
}
getValueFlag_ = 0;
callParamCallbacks();
}
//epicsEventSignal(this->doneWorkingEventId);
}
// Disconnect
// OpenComms only works for Windows-style numbering of COM ports
//commStatus_ = OpenComms(false, 1, 0);
commStatus_ = OpenCommsFromDevice(false, serialPort_);
status = pasynManager->exceptionDisconnect(this->pasynUserSelf);
Linkam::~Linkam()
{
// Force the controller to disconnect
disconnect(this->pasynUserSelf);
}
}
asynStatus Linkam::connect(asynUser *pasynUser)
......@@ -62,29 +211,20 @@ asynStatus Linkam::connect(asynUser *pasynUser)
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: Connecting...\n", driverName, functionName);
/*
* Wrapped call to LinkamCommsDll.Comms.OpenComms()
*
* OpenComms(
* true, bool bConnect: set to true to connect and false to disconnect
* 1, UInt32 u32Commtype: Connection protocol (0: USB, 1: Serial)
* 3); UInt32 u32CommPort: Set to the COMM port that the controller is connected to. (e.g. COMM port 3)
*/
// OpenComms only works for Windows-style numbering of COM ports
//commStatus_ = OpenComms(true, 1, 0);
this->lock();
commStatus_ = OpenCommsFromDevice(true, serialPort_);
connectFlag_ = 1;
this->unlock();
epicsEventSignal(this->connectEventId);
/* We found the controller and everything is OK. Signal to asynManager that we are connected. */
status = pasynManager->exceptionConnect(this->pasynUserSelf);
/*status = pasynManager->exceptionConnect(this->pasynUserSelf);
if (status) {
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: error calling pasynManager->exceptionConnect, error=%s\n",
driverName, functionName, pasynUserSelf->errorMessage);
return asynError;
}
}*/
return asynSuccess;
}
......@@ -97,20 +237,18 @@ asynStatus Linkam::disconnect(asynUser *pasynUser)
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: Disconnecting...\n", driverName, functionName);
// OpenComms only works for Windows-style numbering of COM ports
//commStatus_ = OpenComms(false, 1, 0);
this->lock();
commStatus_ = OpenCommsFromDevice(false, serialPort_);
connectFlag_ = 0;
this->unlock();
/* We found the controller and everything is OK. Signal to asynManager that we are connected. */
status = pasynManager->exceptionDisconnect(this->pasynUserSelf);
/*status = pasynManager->exceptionDisconnect(this->pasynUserSelf);
if (status) {
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: error calling pasynManager->exceptionDisonnect, error=%s\n",
driverName, functionName, pasynUserSelf->errorMessage);
return asynError;
}
}*/
return asynSuccess;
}
......@@ -160,14 +298,22 @@ asynStatus Linkam::readFloat64(asynUser *pasynUser, epicsFloat64 *value)
asynStatus Linkam::readTemperature(epicsFloat64 *value)
{
int function = this->pasynUserSelf->reason;
static const char *functionName = "readTemperature";
this->lock();
*value = GetValue(u32Heater1TempR);
//*value = GetValue(u32Heater1TempR);
valueToGet_ = u32Heater1TempR;
getValueFlag_ = 1;
asynFunction_ = function;
this->unlock();
epicsEventSignal(this->doWorkEventId);
// might need to wait here to get the value
// There probably isn't a good reason to retain the temperature in a private variable;
// The value is already stored in the parameter library
temperatureRbv_ = *value;
//temperatureRbv_ = *value;
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
"%s:%s, port %s, value = %lf\n",
......@@ -178,12 +324,17 @@ asynStatus Linkam::readTemperature(epicsFloat64 *value)
asynStatus Linkam::readRampLimit(epicsFloat64 *value)
{
int function = this->pasynUserSelf->reason;
static const char *functionName = "readRampLimit";
this->lock();
*value = GetValue(u32Heater1LimitRW);
//*value = GetValue(u32Heater1LimitRW);
valueToGet_ = u32Heater1LimitRW;
getValueFlag_ = 1;
asynFunction_ = function;
this->unlock();
epicsEventSignal(this->doWorkEventId);
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
"%s:%s, port %s, value = %lf\n",
driverName, functionName, this->portName, *value);
......@@ -193,11 +344,16 @@ asynStatus Linkam::readRampLimit(epicsFloat64 *value)
asynStatus Linkam::readRampRate(epicsFloat64 *value)
{
int function = this->pasynUserSelf->reason;
static const char *functionName = "readRampRate";
this->lock();
*value = GetValue(u32Heater1RateRW);
//*value = GetValue(u32Heater1RateRW);
valueToGet_ = u32Heater1RateRW;
getValueFlag_ = 1;
asynFunction_ = function;
this->unlock();
epicsEventSignal(this->doWorkEventId);
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
"%s:%s, port %s, value = %lf\n",
......@@ -208,11 +364,16 @@ asynStatus Linkam::readRampRate(epicsFloat64 *value)
asynStatus Linkam::readHeaterPower(epicsFloat64 *value)
{
int function = this->pasynUserSelf->reason;
static const char *functionName = "readHeaterPower";
this->lock();
*value = GetValue(u32Heater1PowerR);
//*value = GetValue(u32Heater1PowerR);
valueToGet_ = u32Heater1PowerR;
getValueFlag_ = 1;
asynFunction_ = function;
this->unlock();
epicsEventSignal(this->doWorkEventId);
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
"%s:%s, port %s, value = %lf\n",
......@@ -238,12 +399,12 @@ asynStatus Linkam::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
if (function == rampLimitOutValue_) {
// Read the temperature from the controller
status = setRampLimit(value);
//status = setRampLimit(value);
} else if (function == rampRateOutValue_) {
// Read the temperature from the controller
status = setRampRate(value);
//status = setRampRate(value);
} else {
status = asynPortDriver::writeFloat64(pasynUser,value);
......
......@@ -16,6 +16,7 @@ static const char *driverName = "Linkam";
#define u32Heater1LimitRW 2
#define u32Heater1PowerR 3
static void LinkamMonoTaskC(void *drvPvt);
/* These are the drvInfo strings that are used to identify the parameters.
* They are used by asyn clients, including standard asyn device support */
......@@ -41,6 +42,8 @@ public:
virtual asynStatus disconnect(asynUser *pasynUser);
virtual asynStatus connect(asynUser *pasynUser);
virtual ~Linkam();
/* LinkamMonoTask should be private, but gets called from C, so must be public */
void LinkamMonoTask();
protected:
int temperatureInValue_;
......@@ -68,6 +71,19 @@ private:
float temperatureRbv_;
char* wrapperVersion_;
char* libraryVersion_;
//
short connectFlag_;
short disconnectFlag_;
short getValueFlag_;
unsigned int valueToGet_;
unsigned int asynFunction_;
//
epicsEventId connectEventId;
epicsEventId doWorkEventId;
epicsEventId initEventId;
//
char currentPath_[FILENAME_MAX];
};
#define NUM_PARAMS ((int)(&LAST_LINKAM_PARAM - &FIRST_LINKAM_PARAM + 1))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment