Files
sics/site_ansto/hardsup/cameradriver.c
Ferdi Franceschini fdbb0456ad The camera driver can now send meta data such as the motor positions to the camera server.
An auxiliary command has been added so we can set string values on the camera driver for the meta data.
2014-07-31 15:45:03 +10:00

1060 lines
30 KiB
C

/**
* \file cameradriver.c
* \brief This provides the IO layer which feeds inputs from a user or
* the camera server to the state machine, and then sends any state machine
* output back to SICS or the camera.
*
* \Author Ferdi Franceschini February 2013
*
* Copyright: see file Copyright.txt
*/
#include <limits.h>
#include <errno.h>
#include <string.h>
#include <sics.h>
#include <obdes.h>
#include <countdriv.h>
#include <nwatch.h>
#include <asyncqueue.h>
#include <math.h>
#include "camera.h"
#define NAMELEN 32
#define IFMTLEN 4
#define ERRLEN 256
#define MSGLEN 512
#define MAX_META_COUNT 32
#define MAX_SCANVAR_COUNT 16
enum camstates {idle, acquiring, processing, saving};
#define CAMDRIV_ERRTABLE \
TR(ENONE, "OK") \
TR(EFAIL, "command failed") \
TR(EBUSYACQ, "camera busy acquiring image") \
TR(EBUSYSAVE, "camera busy saving image") \
TE(EBUSYPROC, "camera busy processing image")
#define TR(a,b) a,
#define TE(a,b) a
enum errcodes {CAMDRIV_ERRTABLE};
#undef TR
#undef TE
#define TR(a,b) b,
#define TE(a,b) b
static char *errmsg[] = {CAMDRIV_ERRTABLE};
#undef TR
#undef TE
#define CAMDRIV_PARTABLE \
TR(CLOCK, "clock") \
TR(BIN, "bin") \
TR(SIZE, "size") \
TR(GAIN, "gain") \
TR(FLIP, "flip") \
TR(XSTART, "xstart") \
TR(YSTART, "ystart") \
TR(XEND, "xend") \
TR(YEND, "yend") \
TR(EXPOSURE, "exposure") \
TR(TEMP, "temperature") \
TR(THRESH, "threshold") \
TR(SHOPT, "shutteropentime") \
TE(SHCLT, "shutterclosetime")
#define TR(a,b) 1+
#define TE(a,b) 1
static int NUMCAMPAR = CAMDRIV_PARTABLE;
#undef TR
#undef TE
#define FLIP_TABLE \
TR(NORMAL, "normal") \
TR(INVINT, "invintensity") \
TR(NORMFH, "normfh") \
TR(NORMFV, "normfv") \
TR(NORMFHV, "normfhv") \
TR(INVFH, "invfh") \
TR(INVFV, "invfv") \
TE(INVFHV, "invfhv")
#define TR(a,b) a,
#define TE(a,b) a
enum campar {CAMDRIV_PARTABLE, MULTI, DEBUG};
enum flipval {FLIP_TABLE};
#undef TR
#undef TE
#define TR(a,b) b,
#define TE(a,b) b
static char *cacmdstr[] = {CAMDRIV_PARTABLE, "multi", "debug", NULL};
static char *flipcmdstr[] = {FLIP_TABLE, NULL};
#undef TR
#undef TE
#define UPDATE_SETTINGS_CFG 1
#define CLEAR_META_CFG 2
#define UPDATE_META_CFG 4
#define UPDATE_SCANVAR_CFG 8
#define UPDATE_FILE_CFG 16
typedef struct {
char path[MSGLEN];
char basename[MSGLEN];
long startnumber;
char imageformat[IFMTLEN];
char experimentdetail[MSGLEN];
} filecfg_t;
typedef struct {
float clockMHz;
float bin;
float size;
float gain;
enum flipval flip;
float xstart;
float ystart;
float xend;
float yend;
float exposure;
float temp;
float thresh;
float shopt;
float shclt;
int updatecfg;
filecfg_t file;
char meta_list[MAX_META_COUNT][MSGLEN];
char scanvar_list[MAX_SCANVAR_COUNT][NAMELEN];
pDummy scanvar_dummy[MAX_SCANVAR_COUNT];
pIDrivable pscanvar[MAX_SCANVAR_COUNT];
int meta_count;
int scanvar_count;
} camcfg_t;
typedef struct {
pObjectDescriptor pDes;
int debug;
char *asynq;
camsm_t state_machine;
pNWTimer state_timer;
int status;
enum errcodes camError;
camcfg_t camera;
pAsyncUnit asyncUnit;
SicsInterp *pSics;
} CamObj;
/* Camera communications and protocol handlers */
static pAsyncProtocol CAM_Protocol = NULL;
static int cb_state_timer(void *ctx, int mode);
static int cb_getstate(pAsyncTxn txn);
static int CamSet(CounterDriver *cntrData, char *name, int iCter, float fVal);
/* if emsg == NULL conversion OK else if emsg == num not an integer else emsg == error message */
long getlong(char *num, char *emsg) {
long val = 0;
char *endptr;
errno = 0;
emsg = NULL;
val = strtol(num, &endptr, 10);
if ( (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0) )
emsg = strerror(errno);
if (endptr == num)
emsg = num;
return val;
}
static void CAM_Notify(void* context, int event) {
CamObj *self = (CamObj *) context;
switch (event) {
case AQU_DISCONNECT:
SICSLogWrite("CAM:(AQU_DISCONNECT)", eLogError);
if (self->state_timer) {
NetWatchRemoveTimer(self->state_timer);
self->state_timer=0;
}
break;
case AQU_RECONNECT:
SICSLogWrite("CAM:(AQU_RECONNECT)", eLogError);
NetWatchRegisterTimerPeriodic(&self->state_timer, 2000, 500, cb_state_timer, self);
break;
}
return;
}
static int CAM_Tx(pAsyncProtocol p, pAsyncTxn txn) {
if (txn == NULL) {
return 0;
}
txn->txn_status = ATX_ACTIVE;
if (AsyncUnitWrite(txn->unit, txn->out_buf, txn->out_len) < 0) {
return 0;
}
return 1;
}
int defaultHandleInput(pAsyncProtocol p, pAsyncTxn txn, int ch);
static int CAM_Rx(pAsyncProtocol p, pAsyncTxn txn, int ch) {
int ret = 1;
if (ch == '\r')
ret = 1;
else if (ch == '\n')
ret = AQU_POP_CMD;
else if (txn->inp_idx < txn->inp_len)
txn->inp_buf[txn->inp_idx++] = ch;
else
ret = AQU_POP_CMD;
return ret;
}
static int CAM_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
if (event == AQU_TIMEOUT) {
pTxn->txn_status = ATX_TIMEOUT;
return AQU_POP_CMD;
}
return AQU_POP_CMD;
}
void CameraInitProtocol(SicsInterp *pSics) {
if (CAM_Protocol == NULL) {
CAM_Protocol = AsyncProtocolCreate(pSics, "CAMERA", NULL, NULL);
CAM_Protocol->sendCommand = CAM_Tx;
CAM_Protocol->handleInput = CAM_Rx;
CAM_Protocol->prepareTxn = NULL;
CAM_Protocol->killPrivate = NULL;
CAM_Protocol->handleEvent = CAM_Ev;
#if 0
CAM_Protocol->sendTerminator = strdup("\r\n");
CAM_Protocol->replyTerminator[0] = strdup("\r\n");
#endif
}
}
/* CounterDriver interface functions */
static int CamGetStatus(CounterDriver *cntrData, float *fControl) {
CamObj *camdrv= (CamObj *)cntrData->pData;
return camdrv->status;
}
/* \brief run_sm, call the state machine with the given input.
* \param self, driver context including current state
* \param ev_sym, input event
*/
static void run_sm(CamObj *self, enum event_codes ev_sym) {
char *sscur, *ssnext, *esout, message[MSGLEN+1];
if (self->debug) {
sscur = strstate(self->state_machine.Sc);
snprintf(message, MSGLEN, "DEBUG:(run_sm) Scurr:%s Ei:%s",
sscur,event_names[ev_sym]);
SICSLogWrite(message, eLog);
}
camdriv_input(self, &self->state_machine, ev_sym);
if (self->debug) {
ssnext = strstate(self->state_machine.Sc), SSLEN;
esout = strevent(self->state_machine.Eo), ESLEN;
snprintf(message, MSGLEN, "DEBUG:(run_sm) Snext:%s Eo:%s", ssnext, esout);
SICSLogWrite(message, eLog);
}
}
/* Called by the scan command and via the count and countnb subcommands of a
* counter object. Will update the configuration if necessary.
*/
static int CamStart(CounterDriver *cntrData) {
CamObj *self = NULL;
enum event_codes cd_sym;
char logmsg[MSGLEN+1];
self = cntrData->pData;
if (self->debug) {
snprintf(logmsg, MSGLEN, "DEBUG:(CamStart): preset=%f\n",cntrData->fPreset);
SICSLogWrite(logmsg, eLog);
}
CamSet(cntrData, "exposure", 0, cntrData->fPreset);
if (self->state_machine.multi) {
cd_sym = ECD_MLTI_ON;
} else {
cd_sym = ECD_TK_SHOT;
}
run_sm(self, cd_sym);
return 1;
}
static int CamPause(CounterDriver *cntrData) {
return 1;
}
static int CamContinue(CounterDriver *cntrData) {
return 1;
}
static int CamHalt(CounterDriver *cntrData) {
CamObj *self = cntrData->pData;
state_t start_state = {.cl=SCL_RDY, .cm=SCM_IDLE, .dr=SDR_IDLE};
if (self->state_machine.multi) {
run_sm(self, ECD_MLTI_OFF);
} else {
STset(&self->state_machine.Sc, start_state);
EVclr(&self->state_machine.Eo);
self->status = HWIdle;
}
return 1;
}
/* FIXME what should the counter data be set to? Total intensity? */
static int CamReadValues(CounterDriver *cntrData) {
int status, iReplyLen=MSGLEN;
char *cmd="TODO ", pReply[MSGLEN];
CamObj *self = NULL;
return 1;
self = cntrData->pData;
status = AsyncUnitTransact(self->asyncUnit, cmd, strlen(cmd), pReply, &iReplyLen);
return 1;
}
static int CamGetError(CounterDriver *cntrData, int *iCode, char *error, int iErrLen) {
CamObj *camdrv=NULL;
camdrv = (CamObj *) cntrData->pData;
*iCode = camdrv->camError;
camdrv->camError = ENONE;
switch (*iCode) {
case EBUSYACQ:
snprintf(error, (size_t) iErrLen,
"CAM: Can't complete operation, %s", errmsg[EBUSYACQ]);
break;
case EBUSYSAVE:
snprintf(error, (size_t) iErrLen,
"CAM: Can't complete operation, %s", errmsg[EBUSYSAVE]);
break;
case EBUSYPROC:
snprintf(error, (size_t) iErrLen,
"CAM: Can't complete operation, %s", errmsg[EBUSYPROC]);
break;
case ENONE:
snprintf(error, (size_t) iErrLen,
"CAM: Can't complete operation, %s", errmsg[ENONE]);
break;
case EFAIL:
snprintf(error, (size_t) iErrLen, "CAM: %s", errmsg[EFAIL]);
break;
}
return 1;
}
static int CamTryAndFixIt(CounterDriver *cntrData, int iCode) {
return COTERM;
}
static int CamSet(CounterDriver *cntrData, char *name, int iCter, float fVal) {
CamObj *camdriv= (CamObj *)cntrData->pData;
int found=0;
char *cmd;
enum campar id;
enum flipval flip;
for (id=0; (cmd = cacmdstr[id]) != NULL; id++) {
if (strcmp(cmd,name) == 0) {
found=1;
break;
}
}
if (!found) {
return 0;
}
switch (id) {
case DEBUG:
if (fVal == 1)
camdriv->debug = 1;
else
camdriv->debug = 0;
break;
case MULTI:
if (fVal != 0 && fVal != 1) {
return 0;
} else {
camdriv->state_machine.multi = fVal;
}
break;
case CLOCK:
if (fVal > 0) {
camdriv->camera.clockMHz = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case BIN:
if (fVal > 0) {
camdriv->camera.bin = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case SIZE:
if (fVal > 0) {
camdriv->camera.size = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case GAIN:
if (fVal > 0) {
camdriv->camera.gain = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case FLIP:
flip = fVal;
switch (flip) {
case NORMAL:
case INVINT:
case NORMFH:
case NORMFV:
case NORMFHV:
case INVFH:
case INVFV:
case INVFHV:
camdriv->camera.flip = flip;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
break;
default:
return 0;
break;
}
break;
case XSTART:
if (fVal > 0) {
camdriv->camera.xstart = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case YSTART:
if (fVal > 0) {
camdriv->camera.ystart = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case XEND:
if (fVal > 0) {
camdriv->camera.xend = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case YEND:
if (fVal > 0) {
camdriv->camera.yend = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case EXPOSURE:
if (fVal > 0) {
camdriv->camera.exposure = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case TEMP:
camdriv->camera.temp = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
break;
case THRESH:
if (fVal > 0) {
camdriv->camera.thresh = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case SHOPT:
if (fVal > 0) {
camdriv->camera.shopt = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
case SHCLT:
if (fVal > 0) {
camdriv->camera.shclt = fVal;
camdriv->camera.updatecfg |= UPDATE_SETTINGS_CFG;
} else {
return 0;
}
break;
default:
return 0;
}
return 1;
}
static int CamGet(CounterDriver *cntrData, char *name, int iCter, float *fVal) {
CamObj *camdriv= (CamObj *)cntrData->pData;
int found=0;
char *cmd;
enum campar id;
for (id=0; (cmd = cacmdstr[id]) != NULL; id++) {
if (strcmp(cmd,name) == 0) {
found=1;
break;
}
}
if (!found) {
return 0;
}
switch (id) {
case MULTI:
*fVal = (float) camdriv->state_machine.multi;
break;
case CLOCK:
*fVal = camdriv->camera.clockMHz;
break;
case BIN:
*fVal = camdriv->camera.bin;
break;
case SIZE:
*fVal = camdriv->camera.size;
break;
case GAIN:
*fVal = camdriv->camera.gain;
break;
case FLIP:
*fVal = camdriv->camera.flip;
break;
case XSTART:
*fVal = camdriv->camera.xstart;
break;
case YSTART:
*fVal = camdriv->camera.ystart;
break;
case XEND:
*fVal = camdriv->camera.xend;
break;
case YEND:
*fVal = camdriv->camera.yend;
break;
case EXPOSURE:
*fVal = camdriv->camera.exposure;
break;
case TEMP:
*fVal = camdriv->camera.temp;
break;
case THRESH:
*fVal = camdriv->camera.thresh;
break;
case SHOPT:
*fVal = camdriv->camera.shopt;
break;
case SHCLT:
*fVal = camdriv->camera.shclt;
break;
default:
return 0;
}
return 1;
}
static int CamSend(CounterDriver *cntrData, char *pText, char *pReply, int iReplyLen) {
int status;
CamObj *self = NULL;
self = cntrData->pData;
//char *pBuf = (char *)calloc(strlen(pText)+10, sizeof(char));
//sprintf(pBuf, "set meta, %s", pText);
//status = AsyncUnitTransact(self->asyncUnit, pBuf, strlen(pBuf), pReply, &iReplyLen);
status = AsyncUnitTransact(self->asyncUnit, pText, strlen(pText), pReply, &iReplyLen);
//free(pBuf);
if (status <= 0)
return 0;
else
return 1;
}
static int cb_shotcmd(pAsyncTxn txn) {
CamObj *self = (CamObj *) txn->cntx;
char *resp = txn->inp_buf, message[MSGLEN+1];
if (self->debug) {
snprintf(message, MSGLEN, "DEBUG:(cb_shotcmd) Camera reply: %s", resp);
SICSLogWrite(message, eLog);
}
if (strncmp(resp, "OK", 2) != 0) {
self->camError = EFAIL;
return 0;
}
return 1;
}
/**
* \brief Decides if an output message is targeted at the camera or SICS or if
* it should be fed back into the state transition function.
*/
int camdriv_out(void *me, event_t Eo) {
int i, len, pend=0;
char cmd[MSGLEN]="", logmsg[MSGLEN+1]="";
float clock, fVal;
CamObj *self = (CamObj *)me;
if (Eo.ca) {
/* send command to camera */
if (self->debug) {
snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:Eo.ca): ev=%s, output=%s\n",
event_names[Eo.ca], event_signatures[Eo.ca]);
SICSLogWrite(logmsg, eLog);
}
switch (Eo.ca) {
case ECA_TK_SHOT:
len = strlen(event_signatures[ECA_TK_SHOT]);
strncpy(cmd, event_signatures[ECA_TK_SHOT], len);
len = strlen(cmd);
AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN);
break;
case ECA_MLTI_ON:
len = strlen(event_signatures[ECA_MLTI_ON]);
strncpy(cmd, event_signatures[ECA_MLTI_ON], len);
len = strlen(cmd);
AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN);
break;
case ECA_MLTI_OFF:
len = strlen(event_signatures[ECA_MLTI_OFF]);
strncpy(cmd, event_signatures[ECA_MLTI_OFF], len);
len = strlen(cmd);
AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN);
break;
case ECA_CFG:
/* TODO Should we retry sending a command if AsyncUnitSendTxn fails?
* The driver should abort the shot and then try to send the
* configuration the next time a shot is taken. */
if( (self->camera.updatecfg & UPDATE_SETTINGS_CFG) == UPDATE_SETTINGS_CFG) {
clock = self->camera.clockMHz;
snprintf(cmd, MSGLEN,
"set camera,clock=%.*fmhz,bin=%dx,size=%d,gain=%dxhs,flip=%s,xstart=%d,ystart=%d,xend=%d,yend=%d,exposure=%f,temperature=%f,threshold=%d,shutteropentime=%d,shutterclosetime=%d",
clock>=1 ? 0 : 1, clock, (int)self->camera.bin, (int)self->camera.size,
(int)self->camera.gain, flipcmdstr[self->camera.flip],
(int)self->camera.xstart, (int)self->camera.ystart,
(int)self->camera.xend, (int)self->camera.yend, self->camera.exposure,
self->camera.temp, (int)self->camera.thresh, (int)self->camera.shopt,
(int)self->camera.shclt
);
len = strlen(cmd);
self->camera.updatecfg &= ~UPDATE_SETTINGS_CFG;
if (self->debug) {
snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:UPDATE_SETTINGS_CFG): cmd=%s\n", cmd);
SICSLogWrite(logmsg, eLog);
}
AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN);
}
if( (self->camera.updatecfg & CLEAR_META_CFG) == CLEAR_META_CFG) {
snprintf(cmd, MSGLEN, "clear meta");
len = strlen(cmd);
if (self->debug) {
snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:CLEAR_META_CFG): cmd=%s\n", cmd);
SICSLogWrite(logmsg, eLog);
}
AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN);
}
if( (self->camera.updatecfg & UPDATE_META_CFG) == UPDATE_META_CFG) {
//TODO concatenate the meta_list into a comma separated string and send it in MSGLEN chunks.
for (i=0; i < self->camera.meta_count && pend < MSGLEN; i++) {
pend = sprintf(cmd, "set meta,");
pend += snprintf(&cmd[pend], MSGLEN, "%s", self->camera.meta_list[i]);
len = strlen(cmd);
if (self->debug) {
snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:UPDATE_META_CFG): cmd=%s\n", cmd);
SICSLogWrite(logmsg, eLog);
}
AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN);
}
}
if( (self->camera.updatecfg & UPDATE_SCANVAR_CFG) == UPDATE_SCANVAR_CFG) {
pend = sprintf(cmd, "set meta");
//TODO Send in MSGLEN chunks even though the string may never exceed MSGLEN
for (i=0; i < self->camera.scanvar_count && pend < MSGLEN; i++) {
fVal = self->camera.pscanvar[i]->GetValue(self->camera.scanvar_dummy[i], pServ->dummyCon);
pend += snprintf(&cmd[pend], MSGLEN, ",%s=%f", self->camera.scanvar_list[i], fVal);
}
len = strlen(cmd);
if (self->debug) {
snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:UPDATE_SCANVAR_CFG): cmd=%s\n", cmd);
SICSLogWrite(logmsg, eLog);
}
AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN);
}
if( (self->camera.updatecfg & UPDATE_FILE_CFG) == UPDATE_FILE_CFG) {
snprintf(cmd, MSGLEN, "set file,path=%s,basename=%s,startnumber=%ld,imageformat=%s,experimentdetail=%s",
self->camera.file.path, self->camera.file.basename, self->camera.file.startnumber, self->camera.file.imageformat,self->camera.file.experimentdetail);
len = strlen(cmd);
if (self->debug) {
snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out:UPDATE_FILE_CFG): cmd=%s\n", cmd);
SICSLogWrite(logmsg, eLog);
}
AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_shotcmd, self, MSGLEN);
self->camera.updatecfg &= ~UPDATE_FILE_CFG;
}
break;
default:
snprintf(logmsg, MSGLEN, "CAM:(camdriv_out) Unhandled event %s", event_names[Eo.ca]);
SICSLogWrite(logmsg, eLogError);
return -1;
}
return -1;
}
if (Eo.cm) {
snprintf(logmsg, MSGLEN, "TODO:(camdriv_out:Eo.cm): ev=%s, output=%s\n",
event_names[Eo.cm], event_signatures[Eo.cm]);
SICSLogWrite(logmsg, eLogError);
return -1;
}
if (Eo.cd) {
snprintf(logmsg, MSGLEN, "TODO:(camdriv_out:Eo.cm): ev=%s, output=%s\n",
event_names[Eo.cd], event_signatures[Eo.cd]);
SICSLogWrite(logmsg, eLogError);
return -1;
}
if (Eo.dr) {
/* send msg to SICS */
if (self->debug) {
snprintf(logmsg, MSGLEN, "DEBUG:(camdriv_out): ev=%s, output=%s\n",
event_names[Eo.dr], event_signatures[Eo.dr]);
SICSLogWrite(logmsg, eLog);
}
switch (Eo.dr) {
case EDR_IDLE:
self->status = HWIdle;
break;
case EDR_BUSY:
self->status = HWBusy;
break;
case EDR_FAULT:
self->status = HWFault;
break;
default:
snprintf(logmsg, MSGLEN, "CAM:(camdriv_out) Unhandled event %s", event_names[Eo.dr]);
SICSLogWrite(logmsg, eLogError);
return -1;
}
return -1;
}
if (Eo.cl) {
switch (Eo.cl) {
case ECL_RDY:
return ECL_RDY;
break;
default:
snprintf(logmsg, MSGLEN, "CAM:(camdriv_out) Unhandled event %s", event_names[Eo.cl]);
SICSLogWrite(logmsg, eLogError);
return -1;
}
return -1;
}
return -1;
}
static int cb_state_timer(void *ctx, int mode) {
CamObj *self = (CamObj *) ctx;
char errmsg[32]="";
char cmd[MSGLEN];
int len, status;
len = strlen(event_signatures[ECA_GET_STATE]);
strncpy(cmd, event_signatures[ECA_GET_STATE], len);
status = AsyncUnitSendTxn(self->asyncUnit, cmd, len, cb_getstate, self, MSGLEN);
if (status==1) {
return 1;
} else {
snprintf(errmsg, 31, "CAM:(cb_getstate) AsyncUnitSendTxn failed");
SICSLogWrite(errmsg, eLogError);
return 0;
}
}
/* Input from camera state feedback */
static int cb_getstate(pAsyncTxn txn) {
CamObj *self = (CamObj *) txn->cntx;
char *resp = txn->inp_buf, message[MSGLEN+1];
int ret=1, time_rem, time_tot;
enum event_codes ca_sym, cm_sym;
if (txn->txn_status == ATX_TIMEOUT) {
ret = 0;
} else if ( cam_parse_status(resp, &ca_sym, &time_rem, &time_tot) == -1) {
snprintf(message, MSGLEN,
"CAM:(cb_getstate) cam_parse_status failed to parse '%s'",resp);
SICSLogWrite(message, eLogError);
ret = 0;
} else {
if (self->debug) {
snprintf(message, MSGLEN, "DEBUG:(cb_getstate) Camera reply: %s", resp);
SICSLogWrite(message, eLog);
}
cm_sym = camera_model(ca_sym);
run_sm(self, cm_sym);
}
return ret;
}
/* Auxiliary Camera Driver commands */
int cmd_code(char **cmd_list, char *cmd) {
int i;
for (i=0; cmd_list[i] != NULL; i++)
if (strcasecmp(cmd_list[i], cmd) == 0)
return i;
return -1;
}
int file_cmd(CamObj *camdriv, SConnection *pCon, char *subcmd, char *data) {
int i, subcmd_code, retval = 1;
long numval;
enum file_subcmd_codes {PATH, BASENAME, IMAGEFMT, STARTNUM, EXPDETAIL};
char *file_subcmd_names[] = {"path", "name", "format", "startnumber", "detail", NULL};
char *glemsg = NULL, emsg[MSGLEN];
if ( (subcmd_code = cmd_code(file_subcmd_names, subcmd)) == -1) {
return 0;
}
switch (subcmd_code) {
case PATH:
snprintf(camdriv->camera.file.path, MSGLEN, "%s", data);
break;
case BASENAME:
snprintf(camdriv->camera.file.basename, MSGLEN, "%s", data);
break;
case STARTNUM:
numval = getlong(data, glemsg);
if (glemsg == NULL) {
camdriv->camera.file.startnumber = numval;
} else if (glemsg == data) {
snprintf(emsg, MSGLEN, "CAM:(file_cmd) %s is not an integer", data);
SCWrite(pCon, emsg, eError);
retval = 0;
} else {
snprintf(emsg, MSGLEN, "CAM:(file_cmd) %s", glemsg);
SCWrite(pCon, emsg, eError);
retval = 0;
}
break;
case IMAGEFMT:
if (strcasecmp(data, "tif") == 0) {
for (i=0; data[i]; i++) {
data[i] = tolower(data[i]);
}
snprintf(camdriv->camera.file.imageformat, IFMTLEN, "%s", data);
} else {
retval = 0;
}
break;
case EXPDETAIL:
snprintf(camdriv->camera.file.experimentdetail, MSGLEN, "%s", data);
break;
default:
retval = 0;
}
return retval;
}
/**
* \brief Auxiliary command interface which gets around type and string length
* limitations of the CountAction command.
*/
int CamAuxCmd(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) {
char *cmd = NULL;
char message[MSGLEN];
enum auxcmd_codes {CLEAR_META, META, FILECMD, SCANVAR, MOTOR};
char *auxcmd_names[] = {"clearmeta", "meta", "file", "scanvar", "motor", NULL};
int i, code, retval = 1, pend=0;
CamObj *camdriv = (CamObj *)pData;
CommandList *pCom = NULL;
pIDrivable pDriv = NULL;
pDummy pDumData = NULL;
if (argc < 2) {
snprintf(message, MSGLEN, "CAM: You must specify a command");
SCWrite(pCon, message, eError);
return 0;
}
if ( (code = cmd_code(auxcmd_names, argv[1])) == -1 ) {
snprintf(message, MSGLEN, "CAM: %s is not a valid command", argv[1]);
SCWrite(pCon, message, eError);
retval = 0;
goto END;
}
switch (code) {
case CLEAR_META:
camdriv->camera.meta_count = 0;
camdriv->camera.scanvar_count = 0;
camdriv->camera.updatecfg |= CLEAR_META_CFG;
camdriv->camera.updatecfg &= ~UPDATE_META_CFG;
camdriv->camera.updatecfg &= ~UPDATE_SCANVAR_CFG;
break;
case META:
if (argc < 3) {
snprintf(message, MSGLEN, "CAM: Insufficient arguments, the META command requires name=val data");
SCWrite(pCon, message, eError);
retval = 0;
goto END;
}
if (camdriv->camera.meta_count < MAX_META_COUNT) {
for (i=2; i < argc; i++) {
pend += snprintf(&(camdriv->camera.meta_list[camdriv->camera.meta_count][pend]), MSGLEN, "%s ", argv[i]);
}
camdriv->camera.meta_count++;
camdriv->camera.updatecfg |= UPDATE_META_CFG;
} else {
goto END;
}
break;
case SCANVAR:
case MOTOR:
if (argc < 3) {
snprintf(message, MSGLEN, "CAM: Insufficient arguments, the MOTOR/SCANVAR command requires the name of something you can drive like a motor or environment control");
SCWrite(pCon, message, eError);
retval = 0;
goto END;
}
if (camdriv->camera.scanvar_count < MAX_SCANVAR_COUNT) {
pCom = FindCommand(pSics, argv[2]);
if (!pCom) {
snprintf(message, MSGLEN, "CAM: There is no command object for a driveable with this name %s", argv[2]);
SCWrite(pCon, message, eError);
retval = 0;
goto END;
}
pDumData = (pDummy) pCom->pData;
if (!pDumData) {
snprintf(message, MSGLEN, "CAM: There is no data for the command object of a driveable with this name %s", argv[2]);
SCWrite(pCon, message, eError);
retval = 0;
goto END;
}
pDriv = (pIDrivable) pDumData->pDescriptor->GetInterface(pDumData, DRIVEID);
if (!pDriv) {
snprintf(message, MSGLEN, "CAM: %s is not a driveable object", argv[2]);
SCWrite(pCon, message, eError);
retval = 0;
goto END;
}
camdriv->camera.scanvar_dummy[camdriv->camera.scanvar_count] = pDumData;
camdriv->camera.pscanvar[camdriv->camera.scanvar_count] = pDriv;
snprintf(camdriv->camera.scanvar_list[camdriv->camera.scanvar_count++], NAMELEN, "%s", argv[2]);
camdriv->camera.updatecfg |= UPDATE_SCANVAR_CFG;
} else {
snprintf(message, MSGLEN, "CAM: Exceeded maximum number (%d) of driveable objects", MAX_SCANVAR_COUNT);
SCWrite(pCon, message, eError);
retval = 0;
goto END;
}
break;
case FILECMD:
if (argc < 4) {
snprintf(message, MSGLEN, "CAM: Insufficient arguments for the FILE command");
SCWrite(pCon, message, eError);
retval = 0;
goto END;
}
if (file_cmd(camdriv, pCon, argv[2], argv[3]))
camdriv->camera.updatecfg |= UPDATE_FILE_CFG;
else {
snprintf(message, MSGLEN, "CAM: Failed to create camera file configuration");
SCWrite(pCon, message, eError);
retval = 0;
goto END;
}
break;
}
END:
if (cmd != NULL)
free(cmd);
return retval;
}
pCounterDriver CreateCam(SConnection *pCon, char *name, char *asynq) {
char msg[ERRLEN], cmd[MSGLEN], auxcmd[NAMELEN];
int len;
state_t start_state = {.cl=SCL_RDY, .cm=SCM_IDLE, .dr=SDR_IDLE};
pCounterDriver pCntDriv = NULL;
CamObj *pNewCam = NULL;
pNewCam = (CamObj *) malloc(sizeof(CamObj));
memset(pNewCam, 0, sizeof(CamObj));
pNewCam->pDes = CreateDescriptor("CameraCommandObject");
STset(&pNewCam->state_machine.Sc, start_state);
EVclr(&pNewCam->state_machine.Eo);
pNewCam->state_machine.output_fn = camdriv_out;
pNewCam->state_machine.multi = 0;
pNewCam->state_timer = 0;
pNewCam->status = HWIdle;
pNewCam->camError = ENONE;
pNewCam->debug = 1;
pNewCam->camera.updatecfg = 0;
pNewCam->camera.meta_count = 0;
pNewCam->camera.scanvar_count = 0;
pNewCam->camera.file.startnumber = 1;
snprintf(pNewCam->camera.file.imageformat, IFMTLEN, "tif");
pNewCam->camera.file.experimentdetail[0] = '\0';
pNewCam->asynq = strdup(asynq);
pNewCam->pSics = pServ->pSics;
if (!AsyncUnitCreate(asynq, &pNewCam->asyncUnit)) {
snprintf(msg, ERRLEN, "CAM:AsyncQueue %s has not been defined", asynq);
SCWrite(pCon, msg, eError);
return NULL;
}
AsyncUnitSetTimeout(pNewCam->asyncUnit, 60000);
AsyncUnitSetNotify(pNewCam->asyncUnit, pNewCam, CAM_Notify);
pCntDriv = CreateCounterDriver(name, "anstocamera");
if (pCntDriv == NULL)
return NULL;
pCntDriv->GetStatus = CamGetStatus;
pCntDriv->Start = CamStart;
pCntDriv->Pause = CamPause;
pCntDriv->Continue = CamContinue;
pCntDriv->Halt = CamHalt;
pCntDriv->ReadValues = CamReadValues;
pCntDriv->GetError = CamGetError;
pCntDriv->TryAndFixIt = CamTryAndFixIt;
pCntDriv->Set = CamSet;
pCntDriv->Get = CamGet;
pCntDriv->Send = CamSend;
pCntDriv->iNoOfMonitors = 1;
pCntDriv->pData = pNewCam;
len = strlen(event_signatures[ECA_GET_STATE]);
strncpy(cmd, event_signatures[ECA_GET_STATE], len);
NetWatchRegisterTimerPeriodic(&pNewCam->state_timer, 2000, 500, cb_state_timer, pNewCam);
snprintf(auxcmd, NAMELEN, "%s_cmd", name);
AddCommand(pNewCam->pSics, auxcmd, CamAuxCmd, NULL, pNewCam);
return pCntDriv;
}