- bug fixes and improvements
This commit is contained in:
328
ipsdriv.c
328
ipsdriv.c
@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user