- bug fixes and improvements

This commit is contained in:
zolliker
2011-03-25 14:28:45 +00:00
parent ccae9f0d16
commit 1384d9034a
12 changed files with 366 additions and 242 deletions

328
ipsdriv.c
View File

@ -31,27 +31,38 @@ Markus Zolliker, May 2005
#include "fsm.h"
#include "initializer.h"
typedef enum {NOTHING, SWITCH_OFF, RAMP_DOWN,
RAMP_ALMOST, RAMP_ZERO, RAMPED_DOWN} DoThis;
typedef struct {
EaseDriv d;
float current; /* current (in Tesla) */
float persfield; /* persistent field from IPS (in Tesla) */
float lastfield; /* persistent field from last drive */
float confirmfield; /* field confirmed in 1st step */
float ramp; /* actual ramp rate (Tesla/min) */
float maxlimit; /* hard field limit */
int persmode; /* 0: leave switch on, 1: go to persistant mode */
int perswitch; /* state of switch */
int remote; /* 0: local, 1: remote, do not check, 2: remote, check */
int nowait; /* 0: normal, 1: drive finishes immediately, ramp in background */
float current; /* current (in Tesla) */
float persfield; /* persistent field from IPS (in Tesla) */
float lastfield; /* persistent field from last drive */
float confirmfield; /* field confirmed in 1st step */
float ramp; /* actual ramp rate (Tesla/min) */
float maxlimit; /* hard field limit */
float perscurrent; /* current for persistent mode workaround (Tesla) */
float perslimit; /* field limit for activating persistent mode workaround (Tesla) */
float voltage; /* voltage */
float measured; /* measured current */
int persmode; /* 0: delayed persistant mode, 1: go to persistant mode, 2: leave switch on */
int persdelay; /* wait time for delayed persistant mode */
int perswitch; /* state of switch */
int remote; /* 0: local, 1: remote, do not check, 2: remote, check */
int nowait; /* 0: normal, 1: drive finishes immediately, ramp in background */
int perswait; /* wait time for persistent mode workaround (sec) */
int heaterFault;
char *fmt; /* fmt for field */
int force; /* force = 2: put heater switch even when stored field does not match */
time_t swtim; /* time when last switching the heater */
time_t tim;
DoThis dothis;
char *fmt; /* fmt for field */
int force; /* force = 2: put heater switch even when stored field does not match */
time_t swtim; /* time when last switching the heater */
time_t tim; /* outside IpsChangeField: time of last Field Change */
} Ips;
static ParClass ipsClass = { "IPS", sizeof(Ips) };
static char *onOff[] = { "off", "on", NULL };
static char *persMode[] = { "auto", "on", "off", NULL };
/*----------------------------------------------------------------------------*/
static int IpsOk(Ips * drv)
@ -141,7 +152,7 @@ void IpsParDef(void *object)
ParName("persmode");
ParAccess(usUser);
ParEnum(onOff);
ParEnum(persMode);
ParList(0);
ParInt(&drv->persmode, 1);
@ -182,11 +193,43 @@ void IpsParDef(void *object)
ParTail("Tesla/min");
ParFloat(&drv->ramp, 1.0);
ParName("perscurrent");
ParAccess(usUser);
ParFmt(drv->fmt);
ParTail("Tesla");
ParFloat(&drv->perscurrent, 0.0);
ParName("perslimit");
ParAccess(usUser);
ParFmt(drv->fmt);
ParTail("Tesla");
ParFloat(&drv->perslimit, 10.0);
ParName("perswait");
ParAccess(usUser);
ParTail("sec");
ParInt(&drv->perswait, 1800);
ParName("persdelay");
ParAccess(usUser);
ParTail("sec");
ParInt(&drv->persdelay, 1800);
ParName("current");
ParFmt(drv->fmt);
ParTail("Tesla equivalent");
ParFloat(&drv->current, PAR_NAN);
ParName("measured");
ParFmt(drv->fmt);
ParTail("Amps");
ParFloat(&drv->measured, PAR_NAN);
ParName("voltage");
ParFmt(drv->fmt);
ParTail("Volt");
ParFloat(&drv->voltage, PAR_NAN);
ParName("lastfield");
ParSave(1);
ParFloat(&drv->lastfield, PAR_NAN);
@ -256,12 +299,15 @@ static void IpsStatus(Ips * drv)
return;
}
if (ans[6] != '3') {
if (drv->remote == 2) {
if (drv->remote == 2) { /* remote state monitoring local switch */
ParPrintf(drv, eError, "IPS switched to local");
*code = EASE_FAULT;
drv->remote = 1;
drv->remote = 3; /* signal to switch back to C0 local locked */
return;
}
if (ans[6] == '1') {
drv->remote = 3; /* signal to switch back to C0 local locked */
}
if (drv->d.hwstate == HWBusy && drv->d.b.doit == NULL) {
drv->d.hwstate = HWIdle;
drv->d.stopped = 0;
@ -280,6 +326,9 @@ static void IpsStatus(Ips * drv)
if (swi != drv->perswitch || drv->swtim == 0) {
drv->swtim = time(NULL);
drv->perswitch = swi;
if (drv->perswitch && drv->dothis == RAMP_ALMOST) {
drv->dothis = NOTHING;
}
}
}
@ -302,6 +351,7 @@ static long IpsRead(long pc, void *object)
{
Ips *drv = ParCast(&ipsClass, object);
EaseBase *eab = object;
time_t expire, now;
switch (pc) {
default: /* FSM BEGIN ****************************** */
@ -310,20 +360,153 @@ static long IpsRead(long pc, void *object)
return __LINE__;
case __LINE__: /**********************************/
IpsStatus(drv);
rd:
EaseWrite(eab, "R7"); /* read current (in Tesla) */
return __LINE__;
case __LINE__: /**********************************/
drv->current = OxiGet(eab, 3, NULL, drv->current);
EaseWrite(eab, "R2"); /* read measured current (in amps) */
return __LINE__;
case __LINE__: /**********************************/
drv->measured = OxiGet(eab, 3, NULL, drv->measured);
EaseWrite(eab, "R1"); /* read measured voltage */
return __LINE__;
case __LINE__: /**********************************/
drv->voltage = OxiGet(eab, 3, NULL, drv->voltage);
if (drv->perswitch) {
IpsSetField(drv, drv->current);
goto quit;
goto checktodo;
}
EaseWrite(eab, "R18"); /* read persistant field (in Tesla) */
return __LINE__;
case __LINE__: /**********************************/
IpsSetField(drv, OxiGet(eab, 3, NULL, drv->persfield));
checktodo:
now = time(NULL);
if (drv->persmode == 2) { /* persistent mode off */
drv->dothis = NOTHING;
goto nothing;
} else {
if (drv->perswitch) {
if (drv->persmode == 1 || now > drv->tim + drv->persdelay) {
drv->dothis = SWITCH_OFF;
} else {
drv->dothis = NOTHING;
goto nothing;
}
} else if (drv->dothis == RAMP_ALMOST) {
if (now > drv->tim + drv->perswait) {
drv->dothis = RAMP_ZERO;
} else {
goto nothing;
}
} else if (drv->dothis == SWITCH_OFF) {
if (now > drv->swtim + 30) {
drv->dothis = RAMP_DOWN;
} else {
goto nothing;
}
} else {
goto nothing;
}
}
EaseWrite(eab, "C3");
drv->remote = 1; /* remote state */
return __LINE__;
case __LINE__: /**********************************/
switch (drv->dothis) {
case SWITCH_OFF: goto switch_off;
case RAMP_DOWN: goto ramp_down;
case RAMP_ZERO: goto ramp_zero;
}
/* we should never get here */
goto quit;
switch_off:
EaseWrite(eab, "H0");
drv->perswitch = 0;
drv->swtim = time(NULL);
drv->lastfield = drv->current;
EaseParHasChanged();
return __LINE__;
case __LINE__: /**********************************/
ParPrintf(drv, -1, "IPS: go to persistent mode, wait 30 sec for switch");
goto localLocked;
ramp_down:
if (drv->current == 0)
goto localLocked;
if (drv->perscurrent == 0 || drv->persfield < drv->perslimit) {
drv->dothis = RAMP_ZERO;
goto ramp_zero;
}
OxiSet(eab, "J", drv->perscurrent, 3); /* put set point to a low value, above the CLACK value */
return __LINE__;
case __LINE__:
EaseWrite(eab, "A1"); /* goto set (almost zero) */
ParPrintf(drv, -1, "IPS: ramp current to %f (almost zero)", drv->perscurrent);
return __LINE__;
case __LINE__: /**********************************/
drv->tim = time(NULL);
drv->dothis = RAMP_ALMOST;
goto localLocked;
ramp_zero:
EaseWrite(eab, "A2"); /* goto zero */
ParPrintf(drv, -1, "IPS: ramp current to 0");
drv->dothis = RAMPED_DOWN;
return __LINE__;
case __LINE__: /**********************************/
goto localLocked;
nothing:
if (drv->remote != 3) /* NOT signal to switch back to local locked */
goto quit;
localLocked:
EaseWrite(eab, "C0");
drv->remote = 0; /* local state */
return __LINE__;
case __LINE__: /**********************************/
quit:
ParLog(drv);
return 0;
} /* FSM END ******************************************* */
}
/*----------------------------------------------------------------------------*/
static long IpsMeas(long pc, void *object)
{
Ips *drv = ParCast(&ipsClass, object);
EaseBase *eab = object;
switch (pc) {
default: /* FSM BEGIN ****************************** */
EasePchk(drv);
EaseWrite(eab, "X");
return __LINE__;
case __LINE__: /**********************************/
IpsStatus(drv);
EaseWrite(eab, "R2"); /* read measured current (in amps) */
return __LINE__;
case __LINE__: /**********************************/
drv->measured = OxiGet(eab, 3, NULL, drv->measured);
EaseWrite(eab, "R1"); /* read measured voltage */
return __LINE__;
case __LINE__: /**********************************/
drv->voltage = OxiGet(eab, 3, NULL, drv->voltage);
quit:
ParLog(drv);
return 0;
@ -359,6 +542,7 @@ static long IpsStart(long pc, void *object)
} else {
drv->fmt = "%.3f";
}
drv->tim = time(NULL);
FsmCall(IpsRead);
return __LINE__;
case __LINE__: /**********************************/
@ -388,7 +572,7 @@ static long IpsChangeField(long pc, void *object)
drv->d.eMode = EVMonitor; /* finish drive, continue in background */
}
EaseWrite(eab, "C3");
drv->remote = 1;
drv->remote = 1; /* remote state */
return __LINE__;
case __LINE__: /**********************************/
EaseWrite(eab, "F7"); /* switch to tesla on display */
@ -397,10 +581,21 @@ static long IpsChangeField(long pc, void *object)
EaseWrite(eab, "A0"); /* hold */
return __LINE__;
case __LINE__: /**********************************/
FsmCall(IpsRead);
EaseWrite(eab, "R7"); /* read current (in Tesla) */
return __LINE__;
case __LINE__: /**********************************/
drv->remote = 2;
drv->current = OxiGet(eab, 3, NULL, drv->current);
EaseWrite(eab, "R18"); /* read persistant field (in Tesla) */
return __LINE__;
case __LINE__: /**********************************/
IpsSetField(drv, OxiGet(eab, 3, NULL, drv->persfield));
FsmCall(IpsMeas);
return __LINE__;
case __LINE__: /**********************************/
drv->remote = 2; /* remote state monitoring local switch */
if (!IpsOk(drv))
goto finish;
if (drv->lastfield == PAR_NAN) {
@ -409,7 +604,7 @@ static long IpsChangeField(long pc, void *object)
if (fabs(drv->d.targetValue - drv->lastfield) < 1e-5) {
ParPrintf(drv, -1, "IPS: we are already at field %f",
drv->lastfield);
if (drv->persmode) {
if (drv->persmode == 1) {
if (!drv->perswitch)
goto finish;
goto target_reached;
@ -432,15 +627,15 @@ static long IpsChangeField(long pc, void *object)
drv->tim = time(NULL);
stab1:
EaseWrite(eab, "X");
return __LINE__;
case __LINE__: /**********************************/
IpsStatus(drv); /* just check for errors */
EaseWrite(eab, "R7"); /* read current (in Tesla) */
return __LINE__;
case __LINE__: /**********************************/
drv->current = OxiGet(eab, 3, NULL, drv->current);
ParLog(drv);
FsmCall(IpsMeas);
return __LINE__;
case __LINE__: /**********************************/
if (fabs(drv->current - drv->lastfield) > 1e-5)
goto stab1;
@ -448,10 +643,11 @@ static long IpsChangeField(long pc, void *object)
FsmWait(1);
return __LINE__;
case __LINE__: /**********************************/
EaseWrite(eab, "X");
FsmCall(IpsMeas);
return __LINE__;
case __LINE__: /**********************************/
IpsStatus(drv);
if (time(NULL) < drv->tim + 10)
goto stab2; /* stabilize */
@ -467,30 +663,33 @@ static long IpsChangeField(long pc, void *object)
return __LINE__;
case __LINE__: /**********************************/
drv->perswitch = 1;
drv->dothis = NOTHING;
drv->swtim = time(NULL);
wait_open:
delay = drv->swtim + 30 - time(NULL);
delay = drv->swtim + 15 - time(NULL);
if (delay > 0)
ParPrintf(drv, -1, "IPS: wait %d sec to open switch", delay);
start_ramp:
ParLog(drv);
start_ramp:
FsmWait(1);
return __LINE__;
case __LINE__: /**********************************/
EaseWrite(eab, "X");
FsmCall(IpsMeas);
return __LINE__;
case __LINE__: /**********************************/
IpsStatus(drv); /* check for errors */
if (drv->heaterFault) {
if (time(NULL) > drv->swtim + 3) {
ParPrintf(drv, eError, "IPS heater fault");
ParPrintf(drv, eError, "IPS: switch heater not connected");
eab->errCode = EASE_FAULT;
goto off_finish;
}
}
if (time(NULL) < drv->swtim + 30)
if (time(NULL) < drv->swtim + 15)
goto start_ramp; /* wait */
OxiSet(eab, "T", drv->ramp, 3);
return __LINE__;
@ -512,15 +711,16 @@ static long IpsChangeField(long pc, void *object)
return __LINE__;
case __LINE__: /**********************************/
IpsSetField(drv, OxiGet(eab, 3, NULL, drv->current)); /* set drv->current and callback */
EaseWrite(eab, "X");
FsmCall(IpsMeas);
return __LINE__;
case __LINE__: /**********************************/
IpsStatus(drv); /* just check for errors */
EaseWrite(eab, "R9"); /* read back ramp rate (may be sweep limited) */
return __LINE__;
case __LINE__: /**********************************/
ramp = OxiGet(eab, 3, NULL, drv->ramp);
step = ramp / 6; /* step = ramp * 10 sec */
step = ramp / 3; /* step = ramp * 20 sec */
if (step < 0.001)
step = 0.001;
if (drv->d.targetValue > drv->current + step) {
@ -540,63 +740,27 @@ static long IpsChangeField(long pc, void *object)
target_reached:
drv->d.hwstate = HWIdle;
drv->d.eMode = EVMonitor; /* we are at field, drive has finished */
if (!drv->persmode)
if (drv->persmode != 1)
goto hold_finish;
/* but we continue in the background */
drv->tim = time(NULL);
stab3:
ParLog(drv);
FsmWait(1);
return __LINE__;
case __LINE__: /**********************************/
EaseWrite(eab, "X");
FsmCall(IpsMeas);
return __LINE__;
case __LINE__: /**********************************/
IpsStatus(drv); /* just check for errors */
if (time(NULL) < drv->tim + 10)
goto stab3; /* stabilize */
EaseWrite(eab, "A0"); /* hold */
return __LINE__;
case __LINE__: /**********************************/
EaseWrite(eab, "H0");
drv->perswitch = 0;
drv->swtim = time(NULL);
drv->lastfield = drv->current;
EaseParHasChanged();
return __LINE__;
case __LINE__: /**********************************/
ParPrintf(drv, -1, "IPS: wait 30 sec to close switch");
wait_closed:
ParLog(drv);
FsmWait(1);
return __LINE__;
case __LINE__: /**********************************/
EaseWrite(eab, "R18"); /* read persistent field in Tesla */
return __LINE__;
case __LINE__: /**********************************/
fld = OxiGet(eab, 3, NULL, drv->current);
if (fld != drv->lastfield) {
IpsSetField(drv, fld); /* set drv->current and callback */
drv->lastfield = fld;
EaseParHasChanged();
}
EaseWrite(eab, "X");
return __LINE__;
case __LINE__: /**********************************/
IpsStatus(drv);
if (time(NULL) < drv->swtim + 30)
goto wait_closed; /* wait */
if (drv->current == 0)
goto finish;
EaseWrite(eab, "A2"); /* goto zero */
ParPrintf(drv, -1, "IPS: ramp current to 0");
return __LINE__;
case __LINE__: /**********************************/
goto finish;
hold_finish:
EaseWrite(eab, "A0");
return __LINE__;
@ -614,8 +778,9 @@ static long IpsChangeField(long pc, void *object)
finish:
EaseWrite(eab, "C0");
drv->remote = 0;
drv->remote = 0; /* local state */
drv->d.hwstate = HWIdle;
drv->tim = time(NULL); /* time of last field change */
return __LINE__;
case __LINE__: /**********************************/
@ -640,6 +805,7 @@ static int IpsInit(SConnection * con, int argc, char *argv[], int dynamic)
return 0;
drv->d.maxwait = 999999;
drv->d.tolerance = 0.001;
drv->dothis = NOTHING;
return 1;
}