- Added a protocol driver for the munich sputter machine
- Added a multicountsersec to teplace hmcontrol and multicounter - Fixed a case sensitivity bug in haddcheck - Made oscillate work with second generation motors for POLDI - Added a time stamper to trace. Now there will be time stamps in trace files which allow to correlate things from the master log with the trace. - Updated polterwrite. - Updated testprot to work with the behave test SKIPPED: psi/make_gen psi/polterwrite.c psi/psi.c psi/sputterprot.c
This commit is contained in:
520
multicountersec.c
Normal file
520
multicountersec.c
Normal file
@ -0,0 +1,520 @@
|
||||
/**
|
||||
* This is a second generation multicounter. It coordinates counting multiple
|
||||
* HM/CCD with the counter box. It also allows to override transfer such that
|
||||
* such a counter can be used in a scan. As with the ordinary multicounter.
|
||||
* This one is supposed to become the standard multicounter replacing the old
|
||||
* multicounter and the hmcontrol module. The other difference is that the task
|
||||
* mechanism will be used to keep track of counters.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, October 2013
|
||||
*/
|
||||
#include <time.h>
|
||||
#include <sics.h>
|
||||
#include <counter.h>
|
||||
#include <stptok.h>
|
||||
#include <macro.h>
|
||||
#include "sicshipadaba.h"
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static void SecCounterSetError(pCounter self, char *text)
|
||||
{
|
||||
hdbValue v;
|
||||
pHdb node;
|
||||
|
||||
node = GetHipadabaNode(self->pDes->parNode, "error");
|
||||
if(node != NULL){
|
||||
v = MakeHdbText(strdup(text));
|
||||
UpdateHipadabaPar(node,v,NULL);
|
||||
ReleaseHdbValue(&v);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
static void doCountCommand(pHdb self, SConnection *pCon, int command)
|
||||
{
|
||||
pHdb master = NULL, slaves = NULL;
|
||||
char *pPtr, name[80];
|
||||
pICountable pCount = NULL;
|
||||
void *data;
|
||||
|
||||
master = GetHipadabaNode(self,"master");
|
||||
slaves = GetHipadabaNode(self,"slaves");
|
||||
assert(master != NULL);
|
||||
assert(slaves != NULL);
|
||||
|
||||
/*
|
||||
treat master
|
||||
*/
|
||||
data = FindCommandData(pServ->pSics,master->value.v.text,NULL);
|
||||
if(data != NULL){
|
||||
pCount = GetCountableInterface(data);
|
||||
if(pCount != NULL){
|
||||
switch(command){
|
||||
case 1001: /* stop */
|
||||
pCount->Halt(data);
|
||||
break;
|
||||
case 1002: /*pause */
|
||||
pCount->Pause(data,pCon);
|
||||
break;
|
||||
case 1003: /* continue */
|
||||
pCount->Continue(data,pCon);
|
||||
break;
|
||||
case 1011:
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
treat slaves
|
||||
*/
|
||||
pPtr = slaves->value.v.text;
|
||||
while((pPtr = stptok(pPtr,name,sizeof(name),",")) != NULL){
|
||||
data = FindCommandData(pServ->pSics,name,NULL);
|
||||
if(data != NULL){
|
||||
pCount = GetCountableInterface(data);
|
||||
if(pCount != NULL){
|
||||
switch(command){
|
||||
case 1001: /* stop */
|
||||
case 1011:
|
||||
pCount->Halt(data);
|
||||
break;
|
||||
case 1002: /*pause */
|
||||
pCount->Pause(data,pCon);
|
||||
break;
|
||||
case 1003: /* continue */
|
||||
pCount->Continue(data,pCon);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(data == NULL || pCount == NULL){
|
||||
SCPrintf(pCon,eLogError,"ERROR: slave counter %s NOT found or unusable", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
static void startMultiCounting(pHdb self, SConnection *pCon)
|
||||
{
|
||||
pHdb mode = NULL, preset = NULL, master = NULL, slaves = NULL;
|
||||
pHdb sID, mID;
|
||||
char *pPtr, name[80];
|
||||
pICountable pCount = NULL;
|
||||
void *data;
|
||||
long slaveID, masterID;
|
||||
CounterMode eMode;
|
||||
hdbValue v;
|
||||
|
||||
mode = GetHipadabaNode(self,"mode");
|
||||
preset = GetHipadabaNode(self,"preset");
|
||||
master = GetHipadabaNode(self,"master");
|
||||
slaves = GetHipadabaNode(self,"slaves");
|
||||
sID = GetHipadabaNode(self,"slaveID");
|
||||
mID = GetHipadabaNode(self,"masterID");
|
||||
assert(mode != NULL);
|
||||
assert(preset != NULL);
|
||||
assert(master != NULL);
|
||||
assert(slaves != NULL);
|
||||
assert(sID != NULL);
|
||||
assert(mID != NULL);
|
||||
|
||||
if(strcmp(mode->value.v.text,"timer") == 0) {
|
||||
eMode = eTimer;
|
||||
} else {
|
||||
eMode = ePreset;
|
||||
}
|
||||
|
||||
/*
|
||||
start slaves
|
||||
*/
|
||||
slaveID = GetTaskGroupID(pServ->pTasker);
|
||||
pPtr = slaves->value.v.text;
|
||||
while((pPtr = stptok(pPtr,name,sizeof(name),",")) != NULL){
|
||||
data = FindCommandData(pServ->pSics,name,NULL);
|
||||
if(data != NULL){
|
||||
pCount = GetCountableInterface(data);
|
||||
if(pCount != NULL){
|
||||
pCount->SetCountParameters(data,preset->value.v.doubleValue,
|
||||
eMode);
|
||||
masterID = StartCountTask(data,pCon,name);
|
||||
if(masterID < 0) {
|
||||
SCPrintf(pCon,eLogError,"ERROR: failed to start slave %s, aborting", name);
|
||||
doCountCommand(self,pCon,1001);
|
||||
return;
|
||||
} else {
|
||||
AddTaskToGroup(pServ->pTasker,masterID, slaveID);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(data == NULL || pCount == NULL){
|
||||
SCPrintf(pCon,eLogError,"ERROR: slave counter %s NOT found or unusable", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
start master
|
||||
*/
|
||||
data = FindCommandData(pServ->pSics,master->value.v.text,NULL);
|
||||
if(data != NULL){
|
||||
pCount = GetCountableInterface(data);
|
||||
if(pCount != NULL){
|
||||
pCount->SetCountParameters(data,preset->value.v.doubleValue,
|
||||
eMode);
|
||||
masterID = StartCountTask(data,pCon,master->value.v.text);
|
||||
}
|
||||
}
|
||||
|
||||
v = MakeHdbInt(masterID);
|
||||
UpdateHipadabaPar(mID,v,pCon);
|
||||
v = MakeHdbInt(slaveID);
|
||||
UpdateHipadabaPar(sID,v,pCon);
|
||||
|
||||
}
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
static hdbCallbackReturn MultiSecControllCallback(pHdb node,
|
||||
void *userData,
|
||||
pHdbMessage message)
|
||||
{
|
||||
pHdbDataMessage mm = NULL;
|
||||
pHdb self = NULL;
|
||||
int code;
|
||||
SConnection *pCon = NULL;
|
||||
|
||||
mm = GetHdbSetMessage(message);
|
||||
if(mm == NULL){
|
||||
return hdbContinue;
|
||||
}
|
||||
|
||||
code = (int)mm->v->v.doubleValue;
|
||||
pCon = (SConnection *)mm->callData;
|
||||
self = node->mama;
|
||||
assert(self != NULL);
|
||||
|
||||
switch(code){
|
||||
case 1000: /* start */
|
||||
startMultiCounting(self, pCon);
|
||||
break;
|
||||
case 1001: /* stop */
|
||||
doCountCommand(self,pCon,code);
|
||||
break;
|
||||
case 1002: /*pause */
|
||||
doCountCommand(self,pCon,code);
|
||||
break;
|
||||
case 1003: /* continue */
|
||||
doCountCommand(self,pCon,code);
|
||||
break;
|
||||
default:
|
||||
if(pCon != NULL){
|
||||
SCPrintf(pCon,eLogError,"ERROR: control code %d not recognised", code);
|
||||
return hdbAbort;
|
||||
}
|
||||
}
|
||||
|
||||
return hdbContinue;
|
||||
}
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
static int isMultiMasterRunning(pCounter self, SConnection *pCon, int *status)
|
||||
{
|
||||
pHdb mID, master, myStatus, control, ccd, stopTime;
|
||||
hdbValue v;
|
||||
long mlID;
|
||||
void *data;
|
||||
pICountable pCount;
|
||||
float controlVal;
|
||||
|
||||
mID = GetHipadabaNode(self->objectNode,"masterID");
|
||||
master = GetHipadabaNode(self->objectNode,"master");
|
||||
myStatus = GetHipadabaNode(self->objectNode,"status");
|
||||
control = GetHipadabaNode(self->objectNode,"control");
|
||||
ccd = GetHipadabaNode(self->objectNode,"ccd");
|
||||
stopTime = GetHipadabaNode(self->objectNode,"stopTime");
|
||||
assert(mID != NULL);
|
||||
assert(master != NULL);
|
||||
assert(myStatus != NULL);
|
||||
assert(control != NULL);
|
||||
assert(ccd != NULL);
|
||||
assert(stopTime != NULL);
|
||||
|
||||
|
||||
mlID = mID->value.v.intValue;
|
||||
if(mlID == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
data = FindCommandData(pServ->pSics,master->value.v.text,NULL);
|
||||
assert(data != NULL);
|
||||
pCount = GetCountableInterface(data);
|
||||
assert(pCount != NULL);
|
||||
|
||||
if(isTaskIDRunning(pServ->pTasker,mlID)) {
|
||||
*status = pCount->CheckCountStatus(data,pCon);
|
||||
controlVal = GetControlValue((pCounter)data);
|
||||
UpdateHipadabaPar(control,MakeHdbFloat(controlVal),pCon);
|
||||
SecCounterSetError(self,"None");
|
||||
switch(*status){
|
||||
case HWFault:
|
||||
UpdateHipadabaPar(myStatus,MakeHdbText("error"),pCon);
|
||||
UpdateHipadabaPar(stopTime,MakeHdbInt(time(NULL)),pCon);
|
||||
SecCounterSetError(self,"Master counter errror");
|
||||
*status = HWBusy;
|
||||
break;
|
||||
case HWPause:
|
||||
UpdateHipadabaPar(myStatus,MakeHdbText("paused"),pCon);
|
||||
break;
|
||||
case HWNoBeam:
|
||||
UpdateHipadabaPar(myStatus,MakeHdbText("nobeam"),pCon);
|
||||
break;
|
||||
default:
|
||||
*status = HWBusy;
|
||||
UpdateHipadabaPar(myStatus,MakeHdbText("run"),pCon);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
we recently stopped. Mark it so and stop slaves.
|
||||
*/
|
||||
mID->value.v.intValue = 0;
|
||||
*status = HWBusy;
|
||||
UpdateHipadabaPar(myStatus,MakeHdbText("run"),pCon);
|
||||
UpdateHipadabaPar(stopTime,MakeHdbInt(time(NULL)),pCon);
|
||||
if(ccd->value.v.intValue != 1) {
|
||||
doCountCommand(self->objectNode,pCon,1011);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
static int areSlavesRunning(pCounter self, SConnection *pCon, int *status)
|
||||
{
|
||||
pHdb slaveID, myStatus, stopTime, ccd;
|
||||
int i;
|
||||
|
||||
slaveID = GetHipadabaNode(self->objectNode,"slaveID");
|
||||
myStatus = GetHipadabaNode(self->objectNode,"status");
|
||||
stopTime = GetHipadabaNode(self->objectNode,"stopTime");
|
||||
ccd = GetHipadabaNode(self->objectNode,"ccd");
|
||||
assert(slaveID != NULL);
|
||||
assert(myStatus != NULL);
|
||||
assert(stopTime != NULL);
|
||||
assert(ccd != NULL);
|
||||
|
||||
if(isTaskGroupRunning(pServ->pTasker,slaveID->value.v.intValue)){
|
||||
if(ccd->value.v.intValue == 1 && time(NULL) > stopTime->value.v.intValue + 100) {
|
||||
SCWrite(pCon,"WARNING: CCD overrun, restarting counting...", eLogError);
|
||||
self->pCountInt->Halt(self);
|
||||
ReleaseCountLock(self->pCountInt);
|
||||
for(i = 0; i < 100; i++){
|
||||
SicsWait(1);
|
||||
if(!isTaskGroupRunning(pServ->pTasker,slaveID->value.v.intValue)){
|
||||
self->pCountInt->StartCount(self,pCon);
|
||||
UpdateHipadabaPar(myStatus,MakeHdbText("run"),pCon);
|
||||
UpdateHipadabaPar(stopTime,MakeHdbInt(time(NULL)),pCon);
|
||||
*status = HWBusy;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
SCWrite(pCon,"ERROR: failed to stop overrun CCD",eLogError);
|
||||
*status = HWFault;
|
||||
return 0;
|
||||
} else {
|
||||
*status = HWBusy;
|
||||
UpdateHipadabaPar(myStatus,MakeHdbText("run"),pCon);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
*status = HWIdle;
|
||||
UpdateHipadabaPar(myStatus,MakeHdbText("idle"),pCon);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
static void multiEndCounting(pCounter self, SConnection *pCon)
|
||||
{
|
||||
|
||||
InvokeCallBack(self->pCall, COUNTEND, NULL);
|
||||
ReleaseCountLock(self->pCountInt);
|
||||
|
||||
|
||||
}
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
static int MultiSecStatus(void *pData, SConnection * pCon)
|
||||
{
|
||||
int status;
|
||||
void *data;
|
||||
pICountable pCount = NULL;
|
||||
pHdb mID = NULL, sID = NULL, master;
|
||||
pCounter self = (pCounter)pData;
|
||||
|
||||
|
||||
if(isMultiMasterRunning(self,pCon, &status)){
|
||||
return status;
|
||||
}
|
||||
|
||||
if(areSlavesRunning(self,pCon, &status)){
|
||||
return status;
|
||||
}
|
||||
|
||||
multiEndCounting(self,pCon);
|
||||
|
||||
return HWIdle;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int MultiSecTransfer(void *pData, SConnection * pCon)
|
||||
{
|
||||
int i, retVal = OKOK, tclStatus;
|
||||
char pBueffel[132];
|
||||
pCounter pCount = NULL;
|
||||
pHdb transfer;
|
||||
|
||||
pCount = (pCounter) pData;
|
||||
|
||||
transfer = GetHipadabaNode(pCount->objectNode,"transfer");
|
||||
if(transfer != NULL){
|
||||
MacroPush(pCon);
|
||||
tclStatus = Tcl_Eval(InterpGetTcl(pServ->pSics), transfer->value.v.text);
|
||||
if (tclStatus != TCL_OK) {
|
||||
snprintf(pBueffel, 131, "ERROR: TransferScript returned: %s",
|
||||
Tcl_GetStringResult(InterpGetTcl(pServ->pSics)));
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
MacroPop();
|
||||
return HWFault;
|
||||
}
|
||||
MacroPop();
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Forward unknown commands to the master counter
|
||||
-----------------------------------------------------------------------------*/
|
||||
static int MultiInvokeSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
int status;
|
||||
char buffer[132];
|
||||
pHdb master = NULL;
|
||||
pCounter self = (pCounter)pData;
|
||||
void *data = NULL;
|
||||
CommandList *pCom;
|
||||
|
||||
status = InvokeSICSOBJ(pCon, pSics, pData, argc, argv);
|
||||
if (status == -1) {
|
||||
master = GetHipadabaNode(self->objectNode,"master");
|
||||
assert(master != NULL);
|
||||
pCom = FindCommand(pSics,master->value.v.text);
|
||||
if(pCom != NULL){
|
||||
status = pCom->OFunc(pCon,pSics,pCom->pData,argc,argv);
|
||||
}
|
||||
status = 0;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
int MakeMultiSec(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
pCounter pRes = NULL;
|
||||
int status, length;
|
||||
pHdb node, child;
|
||||
|
||||
if(argc < 3) {
|
||||
SCWrite(pCon,"ERROR: need at least a name and length to create a counter",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
length = atoi(argv[2]);
|
||||
|
||||
pRes = CreateSecCounter(pCon,"SingleCounter", argv[1], length);
|
||||
if(pRes == NULL){
|
||||
return 0;
|
||||
}
|
||||
|
||||
pRes->pCountInt->CheckCountStatus = MultiSecStatus;
|
||||
pRes->pCountInt->TransferData = MultiSecTransfer;
|
||||
|
||||
node = pRes->objectNode;
|
||||
child = GetHipadabaNode(node,"control");
|
||||
AppendHipadabaCallback(child,MakeHipadabaCallback(MultiSecControllCallback,NULL,NULL));
|
||||
|
||||
child = MakeSICSHdbPar("master", usMugger, MakeHdbText(""));
|
||||
if (child == NULL) {
|
||||
SCWrite(pCon,"ERROR: out of memory in MakeMultiCounterSec",eError);
|
||||
return 0;
|
||||
} else {
|
||||
SetHdbProperty(child, "__save", "true");
|
||||
AddHipadabaChild(node, child, NULL);
|
||||
}
|
||||
|
||||
child = MakeSICSHdbPar("transfer", usMugger, MakeHdbText(""));
|
||||
if (child == NULL) {
|
||||
SCWrite(pCon,"ERROR: out of memory in MakeMultiCounterSec",eError);
|
||||
return 0;
|
||||
} else {
|
||||
SetHdbProperty(child, "__save", "true");
|
||||
AddHipadabaChild(node, child, NULL);
|
||||
}
|
||||
|
||||
child = MakeSICSHdbPar("error", usMugger, MakeHdbText("None"));
|
||||
if (child == NULL) {
|
||||
SCWrite(pCon,"ERROR: out of memory in MakeMultiCounterSec",eError);
|
||||
return 0;
|
||||
} else {
|
||||
AddHipadabaChild(node, child, NULL);
|
||||
}
|
||||
|
||||
child = MakeSICSHdbPar("slaves", usMugger, MakeHdbText(""));
|
||||
if (child == NULL) {
|
||||
SCWrite(pCon,"ERROR: out of memory in MakeMultiCounterSec",eError);
|
||||
return 0;
|
||||
} else {
|
||||
SetHdbProperty(child, "__save", "true");
|
||||
AddHipadabaChild(node, child, NULL);
|
||||
}
|
||||
|
||||
child = MakeSICSHdbPar("ccd", usMugger, MakeHdbInt(0));
|
||||
if (child == NULL) {
|
||||
SCWrite(pCon,"ERROR: out of memory in MakeMultiCounterSec",eError);
|
||||
return 0;
|
||||
} else {
|
||||
SetHdbProperty(child, "__save", "true");
|
||||
AddHipadabaChild(node, child, NULL);
|
||||
}
|
||||
|
||||
child = MakeSICSHdbPar("stopTime", usInternal, MakeHdbInt(0));
|
||||
if (child == NULL) {
|
||||
SCWrite(pCon,"ERROR: out of memory in MakeMultiCounterSec",eError);
|
||||
return 0;
|
||||
} else {
|
||||
AddHipadabaChild(node, child, NULL);
|
||||
}
|
||||
|
||||
child = MakeSICSHdbPar("masterID", usInternal, MakeHdbInt(0));
|
||||
if (child == NULL) {
|
||||
SCWrite(pCon,"ERROR: out of memory in MakeMultiCounterSec",eError);
|
||||
return 0;
|
||||
} else {
|
||||
AddHipadabaChild(node, child, NULL);
|
||||
}
|
||||
child = MakeSICSHdbPar("slaveID", usInternal, MakeHdbInt(0));
|
||||
if (child == NULL) {
|
||||
SCWrite(pCon,"ERROR: out of memory in MakeMultiCounterSec",eError);
|
||||
return 0;
|
||||
} else {
|
||||
AddHipadabaChild(node, child, NULL);
|
||||
}
|
||||
|
||||
status =
|
||||
AddCommand(pSics, argv[1], MultiInvokeSICSOBJ, DeleteCounter,
|
||||
(void *) pRes);
|
||||
if (status != 1) {
|
||||
SCPrintf(pCon,eError, "ERROR: duplicate command %s not created", argv[1]);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
Reference in New Issue
Block a user